diff --git a/Content.Client/Conveyor/Visualizers/ConveyorVisualizer.cs b/Content.Client/Conveyor/Visualizers/ConveyorVisualizer.cs
index aabad00639..04ffc65b7f 100644
--- a/Content.Client/Conveyor/Visualizers/ConveyorVisualizer.cs
+++ b/Content.Client/Conveyor/Visualizers/ConveyorVisualizer.cs
@@ -26,17 +26,18 @@ namespace Content.Client.Conveyor.Visualizers
return;
}
- appearance.TryGetData(ConveyorVisuals.State, out ConveyorState state);
-
- var texture = state switch
+ if (appearance.TryGetData(ConveyorVisuals.State, out ConveyorState state))
{
- ConveyorState.Off => _stateStopped,
- ConveyorState.Forward => _stateRunning,
- ConveyorState.Reversed => _stateReversed,
- _ => throw new ArgumentOutOfRangeException()
- };
+ var texture = state switch
+ {
+ ConveyorState.Off => _stateStopped,
+ ConveyorState.Forward => _stateRunning,
+ ConveyorState.Reversed => _stateReversed,
+ _ => throw new ArgumentOutOfRangeException()
+ };
- sprite.LayerSetState(0, texture);
+ sprite.LayerSetState(0, texture);
+ }
}
public override void InitializeEntity(IEntity entity)
diff --git a/Content.Client/Recycling/RecyclerVisualizer.cs b/Content.Client/Recycling/RecyclerVisualizer.cs
index f831372b4c..d7a3974a15 100644
--- a/Content.Client/Recycling/RecyclerVisualizer.cs
+++ b/Content.Client/Recycling/RecyclerVisualizer.cs
@@ -1,4 +1,5 @@
-using Content.Shared.Recycling;
+using Content.Shared.Conveyor;
+using Content.Shared.Recycling;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
@@ -9,11 +10,11 @@ namespace Content.Client.Recycling
[UsedImplicitly]
public class RecyclerVisualizer : AppearanceVisualizer
{
- [DataField("state_clean")]
- private string? _stateClean;
+ [DataField("state_on")]
+ private string _stateOn = "grinder-o1";
- [DataField("state_bloody")]
- private string? _stateBloody;
+ [DataField("state_off")]
+ private string _stateOff = "grinder-o0";
public override void InitializeEntity(IEntity entity)
{
@@ -25,10 +26,7 @@ namespace Content.Client.Recycling
return;
}
- appearance.TryGetData(RecyclerVisuals.Bloody, out bool bloody);
- sprite.LayerSetState(RecyclerVisualLayers.Bloody, bloody
- ? _stateBloody
- : _stateClean);
+ UpdateAppearance(appearance, sprite);
}
public override void OnChangeData(AppearanceComponent component)
@@ -40,15 +38,28 @@ namespace Content.Client.Recycling
return;
}
- component.TryGetData(RecyclerVisuals.Bloody, out bool bloody);
- sprite.LayerSetState(RecyclerVisualLayers.Bloody, bloody
- ? _stateBloody
- : _stateClean);
+ UpdateAppearance(component, sprite);
+ }
+
+ private void UpdateAppearance(AppearanceComponent component, ISpriteComponent sprite)
+ {
+ var state = _stateOff;
+ if (component.TryGetData(ConveyorVisuals.State, out ConveyorState conveyorState) && conveyorState != ConveyorState.Off)
+ {
+ state = _stateOn;
+ }
+
+ if (component.TryGetData(RecyclerVisuals.Bloody, out bool bloody) && bloody)
+ {
+ state += "bld";
+ }
+
+ sprite.LayerSetState(RecyclerVisualLayers.Main, state);
}
}
public enum RecyclerVisualLayers : byte
{
- Bloody
+ Main
}
}
diff --git a/Content.Server/Conveyor/ConveyorComponent.cs b/Content.Server/Conveyor/ConveyorComponent.cs
index 175f9faa2f..909a91d6fb 100644
--- a/Content.Server/Conveyor/ConveyorComponent.cs
+++ b/Content.Server/Conveyor/ConveyorComponent.cs
@@ -1,9 +1,11 @@
+using System.Collections.Generic;
using Content.Server.Items;
using Content.Server.MachineLinking.Components;
using Content.Server.Power.Components;
using Content.Shared.Conveyor;
using Content.Shared.MachineLinking;
using Robust.Server.GameObjects;
+using Robust.Shared.Analyzers;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
@@ -14,151 +16,29 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.Conveyor
{
[RegisterComponent]
+ [Friend(typeof(ConveyorSystem))]
public class ConveyorComponent : Component
{
public override string Name => "Conveyor";
- [ViewVariables] private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
-
///
/// The angle to move entities by in relation to the owner's rotation.
///
[ViewVariables(VVAccess.ReadWrite)]
[DataField("angle")]
- private Angle _angle = Angle.Zero;
-
- public float Speed => _speed;
+ public Angle Angle = Angle.Zero;
///
/// The amount of units to move the entity by per second.
///
[ViewVariables(VVAccess.ReadWrite)]
[DataField("speed")]
- private float _speed = 2f;
+ public float Speed = 2f;
- 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
- ///
- public Angle GetAngle()
- {
- var adjustment = _state == ConveyorState.Reversed ? MathHelper.Pi : 0;
- var radians = MathHelper.DegreesToRadians(_angle);
-
- return new Angle(Owner.Transform.LocalRotation.Theta + radians + adjustment);
- }
-
- public bool CanRun()
- {
- if (State == ConveyorState.Off)
- {
- return false;
- }
-
- if (Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) &&
- !receiver.Powered)
- {
- return false;
- }
-
- if (Owner.HasComponent())
- {
- return false;
- }
-
- return true;
- }
-
- public bool CanMove(IEntity entity)
- {
- // TODO We should only check status InAir or Static or MapGrid or /mayber/ container
- if (entity == Owner)
- {
- return false;
- }
-
- if (!entity.TryGetComponent(out IPhysBody? physics) ||
- physics.BodyType == BodyType.Static)
- {
- return false;
- }
-
- if (entity.HasComponent())
- {
- return false;
- }
-
- if (entity.HasComponent())
- {
- return false;
- }
-
- if (entity.IsInContainer())
- {
- return false;
- }
-
- return true;
- }
-
- public void SetState(TwoWayLeverSignal signal)
- {
- State = signal switch
- {
- TwoWayLeverSignal.Left => ConveyorState.Reversed,
- TwoWayLeverSignal.Middle => ConveyorState.Off,
- TwoWayLeverSignal.Right => ConveyorState.Forward,
- _ => ConveyorState.Off
- };
- }
+ public ConveyorState State;
}
}
diff --git a/Content.Server/Conveyor/ConveyorSystem.cs b/Content.Server/Conveyor/ConveyorSystem.cs
index c416b77f5d..8edda86258 100644
--- a/Content.Server/Conveyor/ConveyorSystem.cs
+++ b/Content.Server/Conveyor/ConveyorSystem.cs
@@ -1,15 +1,29 @@
-using Content.Server.MachineLinking.Events;
+using System.Collections.Generic;
+using Content.Server.Items;
+using Content.Server.MachineLinking.Events;
using Content.Server.MachineLinking.Models;
+using Content.Server.Power.Components;
+using Content.Server.Recycling.Components;
using Content.Server.Stunnable.Components;
+using Content.Shared.Conveyor;
using Content.Shared.MachineLinking;
+using Content.Shared.Movement.Components;
using Content.Shared.Notification.Managers;
+using Robust.Server.GameObjects;
+using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
using Robust.Shared.Localization;
+using Robust.Shared.Maths;
+using Robust.Shared.Physics;
+using Robust.Shared.Physics.Dynamics;
namespace Content.Server.Conveyor
{
public class ConveyorSystem : EntitySystem
{
+ [Dependency] private IEntityLookup _entityLookup = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -17,6 +31,27 @@ namespace Content.Server.Conveyor
SubscribeLocalEvent(OnSignalReceived);
SubscribeLocalEvent(OnPortDisconnected);
SubscribeLocalEvent(OnLinkAttempt);
+ SubscribeLocalEvent(OnPowerChanged);
+ }
+
+ private void OnPowerChanged(EntityUid uid, ConveyorComponent component, PowerChangedEvent args)
+ {
+ UpdateAppearance(component);
+ }
+
+ private void UpdateAppearance(ConveyorComponent component)
+ {
+ if (component.Owner.TryGetComponent(out var appearance))
+ {
+ if (component.Owner.TryGetComponent(out var receiver) && receiver.Powered)
+ {
+ appearance.SetData(ConveyorVisuals.State, component.State);
+ }
+ else
+ {
+ appearance.SetData(ConveyorVisuals.State, ConveyorState.Off);
+ }
+ }
}
private void OnLinkAttempt(EntityUid uid, ConveyorComponent component, LinkAttemptEvent args)
@@ -35,7 +70,7 @@ namespace Content.Server.Conveyor
private void OnPortDisconnected(EntityUid uid, ConveyorComponent component, PortDisconnectedEvent args)
{
- component.SetState(TwoWayLeverSignal.Middle);
+ SetState(component, TwoWayLeverSignal.Middle);
}
private void OnSignalReceived(EntityUid uid, ConveyorComponent component, SignalReceivedEvent args)
@@ -43,9 +78,92 @@ namespace Content.Server.Conveyor
switch (args.Port)
{
case "state":
- component.SetState((TwoWayLeverSignal) args.Value!);
+ SetState(component, (TwoWayLeverSignal) args.Value!);
break;
}
}
+
+ private void SetState(ConveyorComponent component, TwoWayLeverSignal signal)
+ {
+ component.State = signal switch
+ {
+ TwoWayLeverSignal.Left => ConveyorState.Reversed,
+ TwoWayLeverSignal.Middle => ConveyorState.Off,
+ TwoWayLeverSignal.Right => ConveyorState.Forward,
+ _ => ConveyorState.Off
+ };
+ UpdateAppearance(component);
+ }
+
+ public bool CanRun(ConveyorComponent component)
+ {
+ if (component.State == ConveyorState.Off)
+ {
+ return false;
+ }
+
+ if (component.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) &&
+ !receiver.Powered)
+ {
+ return false;
+ }
+
+ if (component.Owner.HasComponent())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// 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
+ ///
+ public Angle GetAngle(ConveyorComponent component)
+ {
+ var adjustment = component.State == ConveyorState.Reversed ? MathHelper.Pi/2 : -MathHelper.Pi/2;
+ var radians = MathHelper.DegreesToRadians(component.Angle);
+
+ return new Angle(component.Owner.Transform.LocalRotation.Theta + radians + adjustment);
+ }
+
+ public IEnumerable<(IEntity, IPhysBody)> GetEntitiesToMove(ConveyorComponent comp)
+ {
+ //todo uuuhhh cache this
+ foreach (var entity in _entityLookup.GetEntitiesIntersecting(comp.Owner, LookupFlags.Approximate))
+ {
+ if (entity.Deleted)
+ {
+ continue;
+ }
+
+ if (entity == comp.Owner)
+ {
+ continue;
+ }
+
+ if (!entity.TryGetComponent(out IPhysBody? physics) ||
+ physics.BodyType == BodyType.Static || physics.BodyStatus == BodyStatus.InAir || entity.IsWeightless())
+ {
+ continue;
+ }
+
+ if (entity.HasComponent())
+ {
+ continue;
+ }
+
+ if (entity.IsInContainer())
+ {
+ continue;
+ }
+
+ yield return (entity, physics);
+ }
+ }
}
}
diff --git a/Content.Server/Physics/Controllers/ConveyorController.cs b/Content.Server/Physics/Controllers/ConveyorController.cs
index bfbd261a25..4322d279a0 100644
--- a/Content.Server/Physics/Controllers/ConveyorController.cs
+++ b/Content.Server/Physics/Controllers/ConveyorController.cs
@@ -18,102 +18,43 @@ namespace Content.Server.Physics.Controllers
public override void UpdateBeforeSolve(bool prediction, float frameTime)
{
base.UpdateBeforeSolve(prediction, frameTime);
+ var system = EntitySystem.Get();
foreach (var comp in ComponentManager.EntityQuery())
{
- Convey(comp, frameTime);
- }
-
- // TODO: Uhh you can probably wrap the recycler's conveying properties into... conveyor
- foreach (var comp in ComponentManager.EntityQuery())
- {
- ConveyRecycler(comp, frameTime);
+ Convey(system, comp, frameTime);
}
}
- private void Convey(ConveyorComponent comp, float frameTime)
+ private void Convey(ConveyorSystem system, ConveyorComponent comp, float frameTime)
{
- // TODO: Use ICollideBehavior and cache intersecting
// Use an event for conveyors to know what needs to run
- if (!comp.CanRun())
+ if (!system.CanRun(comp))
{
return;
}
- var intersecting = IoCManager.Resolve().GetEntitiesIntersecting(comp.Owner, LookupFlags.Approximate | LookupFlags.IncludeAnchored);
- var direction = comp.GetAngle().ToVec();
- Vector2? ownerPos = null;
+ var direction = system.GetAngle(comp).ToVec();
+ var ownerPos = comp.Owner.Transform.WorldPosition;
- foreach (var entity in intersecting)
+ foreach (var (entity, physics) in EntitySystem.Get().GetEntitiesToMove(comp))
{
- if (!comp.CanMove(entity)) continue;
-
- if (!entity.TryGetComponent(out IPhysBody? physics) || physics.BodyStatus == BodyStatus.InAir ||
- entity.IsWeightless()) continue;
-
- ownerPos ??= comp.Owner.Transform.WorldPosition;
- var itemRelativeToConveyor = entity.Transform.WorldPosition - ownerPos.Value;
-
- physics.LinearVelocity += Convey(direction * comp.Speed, frameTime, itemRelativeToConveyor);
+ var itemRelativeToConveyor = entity.Transform.WorldPosition - ownerPos;
+ physics.LinearVelocity += Convey(direction, comp.Speed, frameTime, itemRelativeToConveyor);
}
}
- // TODO Uhhh I did a shit job plz fix smug
- private Vector2 Convey(Vector2 velocityDirection, float frameTime, Vector2 itemRelativeToConveyor)
+ private Vector2 Convey(Vector2 direction, float speed, float frameTime, Vector2 itemRelativeToConveyor)
{
- //gravitating item towards center
- //http://csharphelper.com/blog/2016/09/find-the-shortest-distance-between-a-point-and-a-line-segment-in-c/
- Vector2 centerPoint;
+ if(speed == 0 || direction.Length == 0) return Vector2.Zero;
+ direction = direction.Normalized;
- var t = 0f;
- if (velocityDirection.Length > 0) // if velocitydirection is 0, this calculation will divide by 0
- {
- t = Vector2.Dot(itemRelativeToConveyor, velocityDirection) /
- Vector2.Dot(velocityDirection, velocityDirection);
- }
+ var dirNormal = new Vector2(direction.Y, direction.X);
+ var dot = Vector2.Dot(itemRelativeToConveyor, dirNormal);
- if (t < 0)
- {
- centerPoint = new Vector2();
- }
- else if (t > 1)
- {
- centerPoint = velocityDirection;
- }
- else
- {
- centerPoint = velocityDirection * t;
- }
+ var velocity = direction * speed * 5;
+ velocity += dirNormal * speed * -dot;
- var delta = centerPoint - itemRelativeToConveyor;
- return delta * (400 * delta.Length) * frameTime;
- }
-
- private void ConveyRecycler(RecyclerComponent comp, float frameTime)
- {
- if (!comp.CanRun())
- {
- comp.Intersecting.Clear();
- return;
- }
-
- var direction = Vector2.UnitX;
- Vector2? ownerPos = null;
-
- // TODO: I know it sucks but conveyors need a refactor
- for (var i = comp.Intersecting.Count - 1; i >= 0; i--)
- {
- var entity = comp.Intersecting[i];
-
- if (entity.Deleted || !comp.CanMove(entity) || !IoCManager.Resolve().IsIntersecting(comp.Owner, entity))
- {
- comp.Intersecting.RemoveAt(i);
- continue;
- }
-
- if (!entity.TryGetComponent(out IPhysBody? physics)) continue;
- ownerPos ??= comp.Owner.Transform.WorldPosition;
- physics.LinearVelocity += Convey(direction, frameTime, entity.Transform.WorldPosition - ownerPos.Value);
- }
+ return velocity * frameTime;
}
}
}
diff --git a/Content.Server/Recycling/Components/RecyclerComponent.cs b/Content.Server/Recycling/Components/RecyclerComponent.cs
index 1b321641e6..ea7b4f1de4 100644
--- a/Content.Server/Recycling/Components/RecyclerComponent.cs
+++ b/Content.Server/Recycling/Components/RecyclerComponent.cs
@@ -13,6 +13,7 @@ using Content.Shared.Notification.Managers;
using Content.Shared.Recycling;
using Robust.Server.GameObjects;
using Robust.Server.Player;
+using Robust.Shared.Analyzers;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -27,28 +28,25 @@ namespace Content.Server.Recycling.Components
{
// TODO: Add sound and safe beep
[RegisterComponent]
+ [Friend(typeof(RecyclerSystem))]
public class RecyclerComponent : Component, ISuicideAct
{
public override string Name => "Recycler";
- public List Intersecting { get; set; } = new();
-
///
/// Whether or not sentient beings will be recycled
///
- [ViewVariables(VVAccess.ReadWrite)] [DataField("safe")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("safe")]
internal bool Safe = true;
///
/// The percentage of material that will be recovered
///
- [ViewVariables(VVAccess.ReadWrite)] [DataField("efficiency")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("efficiency")]
internal float Efficiency = 0.25f;
- internal bool Powered =>
- !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) ||
- receiver.Powered;
-
private void Clean()
{
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
@@ -57,53 +55,6 @@ namespace Content.Server.Recycling.Components
}
}
- public bool CanRun()
- {
- if (Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) &&
- !receiver.Powered)
- {
- return false;
- }
-
- if (Owner.HasComponent())
- {
- return false;
- }
-
- return true;
- }
-
- public bool CanMove(IEntity entity)
- {
- if (entity == Owner)
- {
- return false;
- }
-
- if (!entity.TryGetComponent(out IPhysBody? physics) ||
- physics.BodyType == BodyType.Static)
- {
- return false;
- }
-
- if (entity.HasComponent())
- {
- return false;
- }
-
- if (entity.HasComponent())
- {
- return false;
- }
-
- if (entity.IsInContainer())
- {
- return false;
- }
-
- return true;
- }
-
SuicideKind ISuicideAct.Suicide(IEntity victim, IChatManager chat)
{
var mind = victim.PlayerSession()?.ContentData()?.Mind;
diff --git a/Content.Server/Recycling/RecyclerSystem.cs b/Content.Server/Recycling/RecyclerSystem.cs
index 050f09a44c..f66adecb48 100644
--- a/Content.Server/Recycling/RecyclerSystem.cs
+++ b/Content.Server/Recycling/RecyclerSystem.cs
@@ -1,12 +1,17 @@
+using System.Collections.Generic;
+using Content.Server.Power.Components;
using Content.Server.Recycling.Components;
using Content.Shared.Body.Components;
using Content.Shared.Recycling;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Physics;
using Robust.Shared.Physics.Dynamics;
+using Robust.Shared.Utility;
namespace Content.Server.Recycling
{
- internal sealed class RecyclerSystem: EntitySystem
+ internal sealed class RecyclerSystem : EntitySystem
{
public override void Initialize()
{
@@ -21,11 +26,6 @@ namespace Content.Server.Recycling
private void Recycle(RecyclerComponent component, IEntity entity)
{
- if (!component.Intersecting.Contains(entity))
- {
- component.Intersecting.Add(entity);
- }
-
// TODO: Prevent collision with recycled items
// Can only recycle things that are recyclable... And also check the safety of the thing to recycle.
@@ -45,7 +45,8 @@ namespace Content.Server.Recycling
private bool CanGib(RecyclerComponent component, IEntity entity)
{
// We suppose this entity has a Recyclable component.
- return entity.HasComponent() && !component.Safe && component.Powered;
+ return entity.HasComponent() && !component.Safe &&
+ component.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) && receiver.Powered;
}
public void Bloodstain(RecyclerComponent component)
diff --git a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml
index 92cd7d374e..48b2478915 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml
@@ -20,11 +20,17 @@
netsync: false
sprite: Structures/Machines/recycling.rsi
layers:
- - state: grinder-o1
- map: ["enum.RecyclerVisualLayers.Bloody"]
+ - state: grinder-o0
+ map: ["enum.RecyclerVisualLayers.Main"]
- type: Appearance
visuals:
- type: RecyclerVisualizer
- state_clean: grinder-o1
- state_bloody: grinder-o1bld
+ state_on: grinder-o1
+ state_off: grinder-o0
- type: Recycler
+ - type: Conveyor
+ - type: SignalReceiver
+ inputs:
+ - name: state
+ type: Content.Shared.MachineLinking.TwoWayLeverSignal
+ maxConnections: 1
diff --git a/Resources/Prototypes/Entities/Structures/conveyor.yml b/Resources/Prototypes/Entities/Structures/conveyor.yml
index a93d889ddf..3629ebdc63 100644
--- a/Resources/Prototypes/Entities/Structures/conveyor.yml
+++ b/Resources/Prototypes/Entities/Structures/conveyor.yml
@@ -13,12 +13,11 @@
!type:PhysShapeAabb
bounds: "-0.49,-0.49,0.49,0.49"
hard: false
- layer: [Passable]
- mask:
- - Impassable
- - MobImpassable
- - VaultImpassable
- - SmallImpassable
+ layer:
+ - Opaque
+ - Impassable
+ - MobImpassable
+ - VaultImpassable
- type: SnapGrid
- type: Sprite
netsync: false