Files
RobustToolbox/Robust.Client/Physics/JointSystem.cs
2023-09-11 09:42:55 +10:00

94 lines
3.4 KiB
C#

using System.Collections.Generic;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Dynamics.Joints;
using Robust.Shared.Physics.Systems;
namespace Robust.Client.Physics
{
public sealed class JointSystem : SharedJointSystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<JointComponent, ComponentHandleState>(HandleComponentState);
}
private void HandleComponentState(EntityUid uid, JointComponent component, ref ComponentHandleState args)
{
if (args.Current is not JointComponentState jointState) return;
component.Relay = EnsureEntity<JointComponent>(jointState.Relay, uid);
// Initial state gets applied before the entity (& entity's transform) have been initialized.
// So just let joint init code handle that.
if (!component.Initialized)
{
component.Joints.Clear();
foreach (var (id, state) in jointState.Joints)
{
component.Joints[id] = state.GetJoint(EntityManager, uid);
}
return;
}
foreach (var j in AddedJoints)
{
if ((j.BodyAUid == uid || j.BodyBUid == uid) && !jointState.Joints.ContainsKey(j.ID))
ToRemove.Add(j);
}
AddedJoints.ExceptWith(ToRemove);
ToRemove.Clear();
var removed = new List<Joint>();
foreach (var (existing, j) in component.Joints)
{
if (!jointState.Joints.ContainsKey(existing))
removed.Add(j);
}
foreach (var j in removed)
{
RemoveJoint(j);
}
foreach (var (id, state) in jointState.Joints)
{
if (component.Joints.TryGetValue(id, out var joint))
{
joint.ApplyState(state);
continue;
}
var uidA = GetEntity(state.UidA);
var other = uidA == uid ? GetEntity(state.UidB) : uidA;
// Add new joint (if possible).
// Need to wait for BOTH joint components to come in first before we can add it. Yay dependencies!
if (!EntityManager.HasComponent<JointComponent>(other))
continue;
// TODO: if (other entity is outside of PVS range) continue;
// for now, half-assed check until something like PR #3000 gets merged.
if (Transform(other).MapID == MapId.Nullspace)
continue;
// oh jolly what good fun: the joint component state can get handled prior to the transform component state.
// so if our current transform is on another map, this would throw an error.
// so lets just... assume the server state isn't messed up, and defer the joint processing.
// alternatively:
// TODO: component state handling ordering.
if (Transform(uid).MapID == MapId.Nullspace)
{
AddedJoints.Add(state.GetJoint(EntityManager, uid));
continue;
}
AddJoint(state.GetJoint(EntityManager, uid));
}
}
}
}