using System; using Robust.Shared.Analyzers; using Robust.Shared.GameObjects; using Robust.Shared.GameStates; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Physics.Dynamics.Joints; using Robust.Shared.Serialization; namespace Content.Shared.Pulling.Components { // Before you try to add another type than SharedPullingStateManagementSystem, consider the can of worms you may be opening! [NetworkedComponent()] [Friend(typeof(SharedPullingStateManagementSystem))] [RegisterComponent] public sealed class SharedPullableComponent : Component { public float? MaxDistance => PullJoint?.MaxLength; /// /// The current entity pulling this component. /// SharedPullingStateManagementSystem should be writing this. This means definitely not you. /// public EntityUid? Puller { get; set; } /// /// The pull joint. /// SharedPullingStateManagementSystem should be writing this. This means probably not you. /// public DistanceJoint? PullJoint { get; set; } public bool BeingPulled => Puller != null; public EntityCoordinates? MovingTo { get; set; } public override ComponentState GetComponentState() { return new PullableComponentState(Puller); } public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) { base.HandleComponentState(curState, nextState); if (curState is not PullableComponentState state) { return; } if (!state.Puller.HasValue) { EntitySystem.Get().ForceDisconnectPullable(this); return; } if (!state.Puller.Value.IsValid()) { Logger.Error($"Invalid entity {state.Puller.Value} for pulling"); return; } if (Puller == state.Puller) { // don't disconnect and reconnect a puller for no reason return; } if (!IoCManager.Resolve().TryGetComponent(state.Puller.Value, out var comp)) { Logger.Error($"Entity {state.Puller.Value} for pulling had no Puller component"); // ensure it disconnects from any different puller, still EntitySystem.Get().ForceDisconnectPullable(this); return; } EntitySystem.Get().ForceRelationship(comp, this); } protected override void OnRemove() { if (Puller != null) { // This is absolute paranoia but it's also absolutely necessary. Too many puller state bugs. - 20kdc Logger.ErrorS("c.go.c.pulling", "PULLING STATE CORRUPTION IMMINENT IN PULLABLE {0} - OnRemove called when Puller is set!", Owner); } base.OnRemove(); } } [Serializable, NetSerializable] public sealed class PullableComponentState : ComponentState { public readonly EntityUid? Puller; public PullableComponentState(EntityUid? puller) { Puller = puller; } } /// /// Raised when a request is made to stop pulling an entity. /// public sealed class StopPullingEvent : CancellableEntityEventArgs { public EntityUid? User { get; } public StopPullingEvent(EntityUid? uid = null) { User = uid; } } }