#nullable enable using System.Threading.Tasks; using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.MachineLinking; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Shared.GameObjects.Components.Conveyor; using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.Components.MachineLinking; using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Physics; using Content.Shared.Utility; using Robust.Server.GameObjects; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Components.Map; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Conveyor { [RegisterComponent] public class ConveyorComponent : Component, ISignalReceiver, ISignalReceiver { public override string Name => "Conveyor"; [ViewVariables] private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered; /// /// The angle to move entities by in relation to the owner's rotation. /// [ViewVariables(VVAccess.ReadWrite)] private Angle _angle; /// /// The amount of units to move the entity by per second. /// [ViewVariables(VVAccess.ReadWrite)] private float _speed; private ConveyorState _state; /// /// The current state of this conveyor /// [ViewVariables(VVAccess.ReadWrite)] private ConveyorState State { get => _state; set { _state = value; UpdateAppearance(); } } public override void HandleMessage(ComponentMessage message, IComponent? component) { base.HandleMessage(message, component); switch (message) { case PowerChangedMessage powerChanged: OnPowerChanged(powerChanged); break; } } private void OnPowerChanged(PowerChangedMessage e) { UpdateAppearance(); } private void UpdateAppearance() { if (Owner.TryGetComponent(out var appearance)) { if (Powered) { appearance.SetData(ConveyorVisuals.State, _state); } else { appearance.SetData(ConveyorVisuals.State, ConveyorState.Off); } } } /// /// Calculates the angle in which entities on top of this conveyor /// belt are pushed in /// /// /// The angle when taking into account if the conveyor is reversed /// private Angle GetAngle() { var adjustment = _state == ConveyorState.Reversed ? MathHelper.Pi : 0; var radians = MathHelper.DegreesToRadians(_angle); return new Angle(Owner.Transform.LocalRotation.Theta + radians + adjustment); } private bool CanRun() { if (State == ConveyorState.Off) { return false; } if (Owner.TryGetComponent(out PowerReceiverComponent? receiver) && !receiver.Powered) { return false; } if (Owner.HasComponent()) { return false; } return true; } private bool CanMove(IEntity entity) { if (entity == Owner) { return false; } if (!entity.TryGetComponent(out IPhysicsComponent? physics) || physics.Anchored) { return false; } if (entity.HasComponent()) { return false; } if (entity.HasComponent()) { return false; } if (entity.IsInContainer()) { return false; } return true; } public void Update(float frameTime) { if (!CanRun()) { return; } var intersecting = Owner.EntityManager.GetEntitiesIntersecting(Owner, true); var direction = GetAngle().ToVec(); foreach (var entity in intersecting) { if (!CanMove(entity)) { continue; } if (entity.TryGetComponent(out IPhysicsComponent? physics)) { var controller = physics.EnsureController(); controller.Move(direction, _speed, entity.Transform.WorldPosition - Owner.Transform.WorldPosition); } } } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(ref _angle, "angle", 0); serializer.DataField(ref _speed, "speed", 2); } public void TriggerSignal(TwoWayLeverSignal signal) { State = signal switch { TwoWayLeverSignal.Left => ConveyorState.Reversed, TwoWayLeverSignal.Middle => ConveyorState.Off, TwoWayLeverSignal.Right => ConveyorState.Forward, _ => ConveyorState.Off }; } public void TriggerSignal(bool signal) { State = signal ? ConveyorState.Forward : ConveyorState.Off; } } }