diff --git a/Content.Client/Pinpointer/ClientPinpointerSystem.cs b/Content.Client/Pinpointer/ClientPinpointerSystem.cs
index d31aad8432..afa5b23776 100644
--- a/Content.Client/Pinpointer/ClientPinpointerSystem.cs
+++ b/Content.Client/Pinpointer/ClientPinpointerSystem.cs
@@ -1,10 +1,7 @@
using Content.Shared.Pinpointer;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
-using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
-using Robust.Shared.IoC;
-using Robust.Shared.Maths;
namespace Content.Client.Pinpointer
{
@@ -40,9 +37,9 @@ namespace Content.Client.Pinpointer
if (args.Current is not PinpointerComponentState state)
return;
- SetActive(uid, state.IsActive, pinpointer);
- SetDirection(uid, state.DirectionToTarget, pinpointer);
- SetDistance(uid, state.DistanceToTarget, pinpointer);
+ pinpointer.IsActive = state.IsActive;
+ pinpointer.ArrowAngle = state.ArrowAngle;
+ pinpointer.DistanceToTarget = state.DistanceToTarget;
}
private void UpdateAppearance(EntityUid uid, PinpointerComponent? pinpointer = null,
@@ -55,13 +52,13 @@ namespace Content.Client.Pinpointer
_appearance.SetData(uid, PinpointerVisuals.TargetDistance, pinpointer.DistanceToTarget, appearance);
}
- private void UpdateDirAppearance(EntityUid uid, Direction dir,PinpointerComponent? pinpointer = null,
+ private void UpdateArrowAngle(EntityUid uid, Angle angle, PinpointerComponent? pinpointer = null,
AppearanceComponent? appearance = null)
{
if (!Resolve(uid, ref pinpointer, ref appearance))
return;
- _appearance.SetData(uid, PinpointerVisuals.TargetDirection, dir, appearance);
+ _appearance.SetData(uid, PinpointerVisuals.ArrowAngle, angle, appearance);
}
///
@@ -70,20 +67,12 @@ namespace Content.Client.Pinpointer
///
private void UpdateEyeDir(EntityUid uid, PinpointerComponent? pinpointer = null)
{
- if (!Resolve(uid, ref pinpointer))
+ if (!Resolve(uid, ref pinpointer) || !pinpointer.HasTarget)
return;
- var worldDir = pinpointer.DirectionToTarget;
- if (worldDir == Direction.Invalid)
- {
- UpdateDirAppearance(uid, Direction.Invalid, pinpointer);
- return;
- }
-
var eye = _eyeManager.CurrentEye;
- var angle = worldDir.ToAngle() + eye.Rotation;
- var eyeDir = angle.GetDir();
- UpdateDirAppearance(uid, eyeDir, pinpointer);
+ var angle = pinpointer.ArrowAngle + eye.Rotation;
+ UpdateArrowAngle(uid, angle, pinpointer);
}
}
}
diff --git a/Content.Client/Pinpointer/PinpointerVisualizer.cs b/Content.Client/Pinpointer/PinpointerVisualizer.cs
deleted file mode 100644
index 9236fede5b..0000000000
--- a/Content.Client/Pinpointer/PinpointerVisualizer.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using Content.Shared.Pinpointer;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Maths;
-
-namespace Content.Client.Pinpointer
-{
- [UsedImplicitly]
- public sealed class PinpointerVisualizer : AppearanceVisualizer
- {
- [Obsolete("Subscribe to AppearanceChangeEvent instead.")]
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- var entities = IoCManager.Resolve();
- if (!entities.TryGetComponent(component.Owner, out SpriteComponent? sprite))
- return;
-
- // check if pinpointer screen is active
- if (!component.TryGetData(PinpointerVisuals.IsActive, out bool isActive) || !isActive)
- {
- sprite.LayerSetVisible(PinpointerLayers.Screen, false);
- return;
- }
-
- // check if it has direction to target
- sprite.LayerSetVisible(PinpointerLayers.Screen, true);
- sprite.LayerSetRotation(PinpointerLayers.Screen, Angle.Zero);
-
- if (!component.TryGetData(PinpointerVisuals.TargetDirection, out Direction dir) || dir == Direction.Invalid)
- {
- sprite.LayerSetState(PinpointerLayers.Screen, "pinonnull");
- return;
- }
-
- // check distance to target
- if (!component.TryGetData(PinpointerVisuals.TargetDistance, out Distance dis))
- dis = Distance.UNKNOWN;
-
- switch (dis)
- {
- case Distance.REACHED:
- sprite.LayerSetState(PinpointerLayers.Screen, "pinondirect");
- break;
- case Distance.CLOSE:
- sprite.LayerSetState(PinpointerLayers.Screen, "pinonclose");
- sprite.LayerSetRotation(PinpointerLayers.Screen, dir.ToAngle());
- break;
- case Distance.MEDIUM:
- sprite.LayerSetState(PinpointerLayers.Screen, "pinonmedium");
- sprite.LayerSetRotation(PinpointerLayers.Screen, dir.ToAngle());
- break;
- case Distance.FAR:
- case Distance.UNKNOWN:
- sprite.LayerSetState(PinpointerLayers.Screen, "pinonfar");
- sprite.LayerSetRotation(PinpointerLayers.Screen, dir.ToAngle());
- break;
- }
- }
- }
-}
diff --git a/Content.Client/Pinpointer/PinpointerVisualizerSystem.cs b/Content.Client/Pinpointer/PinpointerVisualizerSystem.cs
new file mode 100644
index 0000000000..244dc00f4c
--- /dev/null
+++ b/Content.Client/Pinpointer/PinpointerVisualizerSystem.cs
@@ -0,0 +1,60 @@
+using Content.Shared.Pinpointer;
+using JetBrains.Annotations;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Pinpointer
+{
+ [UsedImplicitly]
+ public sealed class PinpointerVisualizerSystem : VisualizerSystem
+ {
+ protected override void OnAppearanceChange(EntityUid uid, PinpointerComponent component, ref AppearanceChangeEvent args)
+ {
+ base.OnAppearanceChange(uid, component, ref args);
+
+ if (!TryComp(component.Owner, out SpriteComponent? sprite))
+ return;
+
+ // check if pinpointer screen is active
+ if (!args.Component.TryGetData(PinpointerVisuals.IsActive, out bool isActive) || !isActive)
+ {
+ sprite.LayerSetVisible(PinpointerLayers.Screen, false);
+ return;
+ }
+
+ sprite.LayerSetVisible(PinpointerLayers.Screen, true);
+
+ // check distance and direction to target
+ if (!args.Component.TryGetData(PinpointerVisuals.TargetDistance, out Distance dis) ||
+ !args.Component.TryGetData(PinpointerVisuals.ArrowAngle, out Angle angle))
+ {
+ sprite.LayerSetState(PinpointerLayers.Screen, "pinonnull");
+ sprite.LayerSetRotation(PinpointerLayers.Screen, Angle.Zero);
+ return;
+ }
+
+ switch (dis)
+ {
+ case Distance.Reached:
+ sprite.LayerSetState(PinpointerLayers.Screen, "pinondirect");
+ sprite.LayerSetRotation(PinpointerLayers.Screen, Angle.Zero);
+ break;
+ case Distance.Close:
+ sprite.LayerSetState(PinpointerLayers.Screen, "pinonclose");
+ sprite.LayerSetRotation(PinpointerLayers.Screen, angle);
+ break;
+ case Distance.Medium:
+ sprite.LayerSetState(PinpointerLayers.Screen, "pinonmedium");
+ sprite.LayerSetRotation(PinpointerLayers.Screen, angle);
+ break;
+ case Distance.Far:
+ sprite.LayerSetState(PinpointerLayers.Screen, "pinonfar");
+ sprite.LayerSetRotation(PinpointerLayers.Screen, angle);
+ break;
+ case Distance.Unknown:
+ sprite.LayerSetState(PinpointerLayers.Screen, "pinonnull");
+ sprite.LayerSetRotation(PinpointerLayers.Screen, Angle.Zero);
+ break;
+ }
+ }
+ }
+}
diff --git a/Content.Server/Pinpointer/ServerPinpointerSystem.cs b/Content.Server/Pinpointer/ServerPinpointerSystem.cs
index a785ab83d9..a1c7b5af74 100644
--- a/Content.Server/Pinpointer/ServerPinpointerSystem.cs
+++ b/Content.Server/Pinpointer/ServerPinpointerSystem.cs
@@ -26,12 +26,12 @@ namespace Content.Server.Pinpointer
private void OnLocateTarget(HyperspaceJumpCompletedEvent ev)
{
// This feels kind of expensive, but it only happens once per hyperspace jump
- foreach (var uid in ActivePinpointers)
+
+ // todo: ideally, you would need to raise this event only on jumped entities
+ // this code update ALL pinpointers in game
+ foreach (var pinpointer in EntityQuery())
{
- if (TryComp(uid, out var component))
- {
- LocateTarget(uid, component);
- }
+ LocateTarget(pinpointer.Owner, pinpointer);
}
}
@@ -58,9 +58,9 @@ namespace Content.Server.Pinpointer
// because target or pinpointer can move
// we need to update pinpointers arrow each frame
- foreach (var uid in ActivePinpointers)
+ foreach (var pinpointer in EntityQuery())
{
- UpdateDirectionToTarget(uid);
+ UpdateDirectionToTarget(pinpointer.Owner, pinpointer);
}
}
@@ -85,14 +85,14 @@ namespace Content.Server.Pinpointer
foreach (var comp in EntityManager.GetAllComponents(whitelist))
{
- if (!xformQuery.TryGetComponent(comp.Owner, out var compXform) ||
- compXform.MapID != mapId) continue;
+ if (!xformQuery.TryGetComponent(comp.Owner, out var compXform) || compXform.MapID != mapId)
+ continue;
var dist = (_transform.GetWorldPosition(compXform, xformQuery) - worldPos).LengthSquared;
l.TryAdd(dist, comp.Owner);
}
- // return uid with a smallest distacne
+ // return uid with a smallest distance
return l.Count > 0 ? l.First().Value : null;
}
@@ -120,33 +120,34 @@ namespace Content.Server.Pinpointer
if (!Resolve(uid, ref pinpointer))
return;
+ if (!pinpointer.IsActive)
+ return;
+
var target = pinpointer.Target;
if (target == null || !EntityManager.EntityExists(target.Value))
{
- SetDirection(uid, Direction.Invalid, pinpointer);
- SetDistance(uid, Distance.UNKNOWN, pinpointer);
+ SetDistance(uid, Distance.Unknown, pinpointer);
return;
}
var dirVec = CalculateDirection(uid, target.Value);
if (dirVec != null)
{
- var dir = dirVec.Value.GetDir();
- SetDirection(uid, dir, pinpointer);
+ var angle = dirVec.Value.ToWorldAngle();
+ TrySetArrowAngle(uid, angle, pinpointer);
var dist = CalculateDistance(uid, dirVec.Value, pinpointer);
SetDistance(uid, dist, pinpointer);
}
else
{
- SetDirection(uid, Direction.Invalid, pinpointer);
- SetDistance(uid, Distance.UNKNOWN, pinpointer);
+ SetDistance(uid, Distance.Unknown, pinpointer);
}
}
///
/// Calculate direction from pinUid to trgUid
///
- /// Null if failed to caluclate distance between two entities
+ /// Null if failed to calculate distance between two entities
private Vector2? CalculateDirection(EntityUid pinUid, EntityUid trgUid)
{
var xformQuery = GetEntityQuery();
@@ -169,17 +170,17 @@ namespace Content.Server.Pinpointer
private Distance CalculateDistance(EntityUid uid, Vector2 vec, PinpointerComponent? pinpointer = null)
{
if (!Resolve(uid, ref pinpointer))
- return Distance.UNKNOWN;
+ return Distance.Unknown;
var dist = vec.Length;
if (dist <= pinpointer.ReachedDistance)
- return Distance.REACHED;
+ return Distance.Reached;
else if (dist <= pinpointer.CloseDistance)
- return Distance.CLOSE;
+ return Distance.Close;
else if (dist <= pinpointer.MediumDistance)
- return Distance.MEDIUM;
+ return Distance.Medium;
else
- return Distance.FAR;
+ return Distance.Far;
}
}
}
diff --git a/Content.Shared/Pinpointer/PinpointerComponent.cs b/Content.Shared/Pinpointer/PinpointerComponent.cs
index 238b35a053..7e467f14b0 100644
--- a/Content.Shared/Pinpointer/PinpointerComponent.cs
+++ b/Content.Shared/Pinpointer/PinpointerComponent.cs
@@ -24,27 +24,34 @@ namespace Content.Shared.Pinpointer
[DataField("reachedDistance")]
public float ReachedDistance = 1f;
+ ///
+ /// Pinpointer arrow precision in radians.
+ ///
+ [DataField("precision")]
+ public double Precision = 0.09;
+
public EntityUid? Target = null;
public bool IsActive = false;
- public Direction DirectionToTarget = Direction.Invalid;
- public Distance DistanceToTarget = Distance.UNKNOWN;
+ public Angle ArrowAngle;
+ public Distance DistanceToTarget = Distance.Unknown;
+ public bool HasTarget => DistanceToTarget != Distance.Unknown;
}
[Serializable, NetSerializable]
public sealed class PinpointerComponentState : ComponentState
{
public bool IsActive;
- public Direction DirectionToTarget;
+ public Angle ArrowAngle;
public Distance DistanceToTarget;
}
[Serializable, NetSerializable]
public enum Distance : byte
{
- UNKNOWN,
- REACHED,
- CLOSE,
- MEDIUM,
- FAR
+ Unknown,
+ Reached,
+ Close,
+ Medium,
+ Far
}
}
diff --git a/Content.Shared/Pinpointer/PinpointerVisuals.cs b/Content.Shared/Pinpointer/PinpointerVisuals.cs
index fd190f068a..a7e9c8bf0f 100644
--- a/Content.Shared/Pinpointer/PinpointerVisuals.cs
+++ b/Content.Shared/Pinpointer/PinpointerVisuals.cs
@@ -6,7 +6,7 @@ namespace Content.Shared.Pinpointer
public enum PinpointerVisuals : byte
{
IsActive,
- TargetDirection,
+ ArrowAngle,
TargetDistance
}
diff --git a/Content.Shared/Pinpointer/SharedPinpointerSystem.cs b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs
index 775f001019..17e5de8cfd 100644
--- a/Content.Shared/Pinpointer/SharedPinpointerSystem.cs
+++ b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs
@@ -4,13 +4,10 @@ namespace Content.Shared.Pinpointer
{
public abstract class SharedPinpointerSystem : EntitySystem
{
- protected readonly HashSet ActivePinpointers = new();
-
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(GetCompState);
- SubscribeLocalEvent(OnPinpointerShutdown);
}
private void GetCompState(EntityUid uid, PinpointerComponent pinpointer, ref ComponentGetState args)
@@ -18,17 +15,11 @@ namespace Content.Shared.Pinpointer
args.State = new PinpointerComponentState
{
IsActive = pinpointer.IsActive,
- DirectionToTarget = pinpointer.DirectionToTarget,
+ ArrowAngle = pinpointer.ArrowAngle,
DistanceToTarget = pinpointer.DistanceToTarget
};
}
- private void OnPinpointerShutdown(EntityUid uid, PinpointerComponent component, ComponentShutdown _)
- {
- // no need to dirty it/etc: it's shutting down anyway!
- ActivePinpointers.Remove(uid);
- }
-
///
/// Manually set distance from pinpointer to target
///
@@ -45,18 +36,22 @@ namespace Content.Shared.Pinpointer
}
///
- /// Manually set pinpointer arrow direction
+ /// Try to manually set pinpointer arrow direction.
+ /// If difference between current angle and new angle is smaller than
+ /// pinpointer precision, new value will be ignored and it will return false.
///
- public void SetDirection(EntityUid uid, Direction directionToTarget, PinpointerComponent? pinpointer = null)
+ public bool TrySetArrowAngle(EntityUid uid, Angle arrowAngle, PinpointerComponent? pinpointer = null)
{
if (!Resolve(uid, ref pinpointer))
- return;
+ return false;
- if (directionToTarget == pinpointer.DirectionToTarget)
- return;
+ if (pinpointer.ArrowAngle.EqualsApprox(arrowAngle, pinpointer.Precision))
+ return false;
- pinpointer.DirectionToTarget = directionToTarget;
+ pinpointer.ArrowAngle = arrowAngle;
Dirty(pinpointer);
+
+ return true;
}
///
@@ -68,13 +63,7 @@ namespace Content.Shared.Pinpointer
return;
if (isActive == pinpointer.IsActive)
return;
-
- // add-remove pinpointer from update list
- if (isActive)
- ActivePinpointers.Add(uid);
- else
- ActivePinpointers.Remove(uid);
-
+
pinpointer.IsActive = isActive;
Dirty(pinpointer);
}
diff --git a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml
index 905dbe9d9e..48682b4547 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml
@@ -9,6 +9,7 @@
noRot: True
- type: Sprite
netsync: false
+ noRot: True
sprite: Objects/Devices/pinpointer.rsi
layers:
- state: pinpointer
@@ -19,8 +20,6 @@
sprite: Objects/Devices/pinpointer.rsi
- type: Pinpointer
- type: Appearance
- visuals:
- - type: PinpointerVisualizer
- type: entity
name: pinpointer
diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings
index 041587116f..1905f9f55e 100644
--- a/SpaceStation14.sln.DotSettings
+++ b/SpaceStation14.sln.DotSettings
@@ -560,6 +560,8 @@ public sealed class $CLASS$ : Shared$CLASS$ {
True
True
True
+ True
+ True
True
True
True