]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add conditional camera offset based on cursor - Hristov Rework, Part 1 (#31626)
authorSlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com>
Mon, 27 Jan 2025 23:20:45 +0000 (00:20 +0100)
committerGitHub <noreply@github.com>
Mon, 27 Jan 2025 23:20:45 +0000 (00:20 +0100)
20 files changed:
Content.Client/Movement/Components/EyeCursorOffsetComponent.cs [new file with mode: 0644]
Content.Client/Movement/Systems/ContentEyeSystem.cs
Content.Client/Movement/Systems/EyeCursorOffsetSystem.cs [new file with mode: 0644]
Content.Client/Wieldable/WieldableSystem.cs [new file with mode: 0644]
Content.Server/Movement/Components/EyeCursorOffsetComponent.cs [new file with mode: 0644]
Content.Server/Wieldable/WieldableSystem.cs [new file with mode: 0644]
Content.Shared/Camera/GetEyeOffsetEvent.cs
Content.Shared/Camera/GetEyePvsScaleEvent.cs [new file with mode: 0644]
Content.Shared/Camera/SharedCameraRecoilSystem.cs
Content.Shared/Hands/EntitySystems/SharedHandsSystem.Relay.cs
Content.Shared/Movement/Components/CursorOffsetRequiresWieldComponent.cs [new file with mode: 0644]
Content.Shared/Movement/Components/EyeCursorOffsetComponent.cs [new file with mode: 0644]
Content.Shared/Movement/Systems/SharedContentEyeSystem.cs
Content.Shared/Weapons/Melee/Components/MeleeRequiresWieldComponent.cs
Content.Shared/Weapons/Ranged/Components/GunRequiresWieldComponent.cs
Content.Shared/Weapons/Ranged/Components/GunWieldBonusComponent.cs
Content.Shared/Wieldable/Components/IncreaseDamageOnWieldComponent.cs
Content.Shared/Wieldable/Components/WieldableComponent.cs
Content.Shared/Wieldable/SharedWieldableSystem.cs [moved from Content.Shared/Wieldable/WieldableSystem.cs with 99% similarity]
Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml

diff --git a/Content.Client/Movement/Components/EyeCursorOffsetComponent.cs b/Content.Client/Movement/Components/EyeCursorOffsetComponent.cs
new file mode 100644 (file)
index 0000000..5ed1bf4
--- /dev/null
@@ -0,0 +1,19 @@
+using System.Numerics;
+using Content.Client.Movement.Systems;
+using Content.Shared.Movement.Components;
+
+namespace Content.Client.Movement.Components;
+
+[RegisterComponent]
+public sealed partial class EyeCursorOffsetComponent : SharedEyeCursorOffsetComponent
+{
+    /// <summary>
+    /// The location the offset will attempt to pan towards; based on the cursor's position in the game window.
+    /// </summary>
+    public Vector2 TargetPosition = Vector2.Zero;
+
+    /// <summary>
+    /// The current positional offset being applied. Used to enable gradual panning.
+    /// </summary>
+    public Vector2 CurrentPosition = Vector2.Zero;
+}
index 9fbd4b5c37d0b548a2cee0ab787488940856d0fd..518a4a1bd40afaf32ab5b95be64c7c2df5079390 100644 (file)
@@ -1,6 +1,7 @@
 using System.Numerics;
 using Content.Shared.Movement.Components;
 using Content.Shared.Movement.Systems;
+using Robust.Client.GameObjects;
 using Robust.Client.Player;
 
 namespace Content.Client.Movement.Systems;
@@ -52,4 +53,14 @@ public sealed class ContentEyeSystem : SharedContentEyeSystem
     {
         RaisePredictiveEvent(new RequestEyeEvent(drawFov, drawLight));
     }
+
+    public override void FrameUpdate(float frameTime)
+    {
+        base.FrameUpdate(frameTime);
+        var eyeEntities = AllEntityQuery<ContentEyeComponent, EyeComponent>();
+        while (eyeEntities.MoveNext(out var entity, out ContentEyeComponent? contentComponent, out EyeComponent? eyeComponent))
+        {
+            UpdateEyeOffset((entity, eyeComponent));
+        }
+    }
 }
diff --git a/Content.Client/Movement/Systems/EyeCursorOffsetSystem.cs b/Content.Client/Movement/Systems/EyeCursorOffsetSystem.cs
new file mode 100644 (file)
index 0000000..f3bff9e
--- /dev/null
@@ -0,0 +1,91 @@
+using System.Numerics;
+using Content.Client.Movement.Components;
+using Content.Shared.Camera;
+using Content.Shared.Inventory;
+using Content.Shared.Movement.Systems;
+using Robust.Client.Graphics;
+using Robust.Client.Input;
+using Robust.Shared.Map;
+using Robust.Client.Player;
+
+namespace Content.Client.Movement.Systems;
+
+public partial class EyeCursorOffsetSystem : EntitySystem
+{
+    [Dependency] private readonly IEyeManager _eyeManager = default!;
+    [Dependency] private readonly IInputManager _inputManager = default!;
+    [Dependency] private readonly IPlayerManager _player = default!;
+    [Dependency] private readonly SharedTransformSystem _transform = default!;
+    [Dependency] private readonly SharedContentEyeSystem _contentEye = default!;
+    [Dependency] private readonly IMapManager _mapManager = default!;
+    [Dependency] private readonly IClyde _clyde = default!;
+
+    // This value is here to make sure the user doesn't have to move their mouse
+    // all the way out to the edge of the screen to get the full offset.
+    static private float _edgeOffset = 0.9f;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<EyeCursorOffsetComponent, GetEyeOffsetEvent>(OnGetEyeOffsetEvent);
+    }
+
+    private void OnGetEyeOffsetEvent(EntityUid uid, EyeCursorOffsetComponent component, ref GetEyeOffsetEvent args)
+    {
+        var offset = OffsetAfterMouse(uid, component);
+        if (offset == null)
+            return;
+
+        args.Offset += offset.Value;
+    }
+
+    public Vector2? OffsetAfterMouse(EntityUid uid, EyeCursorOffsetComponent? component)
+    {
+        var localPlayer = _player.LocalPlayer?.ControlledEntity;
+        var mousePos = _inputManager.MouseScreenPosition;
+        var screenSize = _clyde.MainWindow.Size;
+        var minValue = MathF.Min(screenSize.X / 2, screenSize.Y / 2) * _edgeOffset;
+
+        var mouseNormalizedPos = new Vector2(-(mousePos.X - screenSize.X / 2) / minValue, (mousePos.Y - screenSize.Y / 2) / minValue); // X needs to be inverted here for some reason, otherwise it ends up flipped.
+
+        if (localPlayer == null)
+            return null;
+
+        var playerPos = _transform.GetWorldPosition(localPlayer.Value);
+
+        if (component == null)
+        {
+            component = EnsureComp<EyeCursorOffsetComponent>(uid);
+        }
+
+        // Doesn't move the offset if the mouse has left the game window!
+        if (mousePos.Window != WindowId.Invalid)
+        {
+            // The offset must account for the in-world rotation.
+            var eyeRotation = _eyeManager.CurrentEye.Rotation;
+            var mouseActualRelativePos = Vector2.Transform(mouseNormalizedPos, System.Numerics.Quaternion.CreateFromAxisAngle(-System.Numerics.Vector3.UnitZ, (float)(eyeRotation.Opposite().Theta))); // I don't know, it just works.
+
+            // Caps the offset into a circle around the player.
+            mouseActualRelativePos *= component.MaxOffset;
+            if (mouseActualRelativePos.Length() > component.MaxOffset)
+            {
+                mouseActualRelativePos = mouseActualRelativePos.Normalized() * component.MaxOffset;
+            }
+
+            component.TargetPosition = mouseActualRelativePos;
+
+            //Makes the view not jump immediately when moving the cursor fast.
+            if (component.CurrentPosition != component.TargetPosition)
+            {
+                Vector2 vectorOffset = component.TargetPosition - component.CurrentPosition;
+                if (vectorOffset.Length() > component.OffsetSpeed)
+                {
+                    vectorOffset = vectorOffset.Normalized() * component.OffsetSpeed;
+                }
+                component.CurrentPosition += vectorOffset;
+            }
+        }
+        return component.CurrentPosition;
+    }
+}
diff --git a/Content.Client/Wieldable/WieldableSystem.cs b/Content.Client/Wieldable/WieldableSystem.cs
new file mode 100644 (file)
index 0000000..2de8379
--- /dev/null
@@ -0,0 +1,49 @@
+using System.Numerics;
+using Content.Client.Movement.Components;
+using Content.Client.Movement.Systems;
+using Content.Shared.Camera;
+using Content.Shared.Hands;
+using Content.Shared.Movement.Components;
+using Content.Shared.Wieldable;
+using Content.Shared.Wieldable.Components;
+using Robust.Client.Timing;
+
+namespace Content.Client.Wieldable;
+
+public sealed class WieldableSystem : SharedWieldableSystem
+{
+    [Dependency] private readonly EyeCursorOffsetSystem _eyeOffset = default!;
+    [Dependency] private readonly IClientGameTiming _gameTiming = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, ItemUnwieldedEvent>(OnEyeOffsetUnwielded);
+        SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, HeldRelayedEvent<GetEyeOffsetRelayedEvent>>(OnGetEyeOffset);
+    }
+
+    public void OnEyeOffsetUnwielded(Entity<CursorOffsetRequiresWieldComponent> entity, ref ItemUnwieldedEvent args)
+    {
+        if (!TryComp(entity.Owner, out EyeCursorOffsetComponent? cursorOffsetComp))
+            return;
+
+        if (_gameTiming.IsFirstTimePredicted)
+            cursorOffsetComp.CurrentPosition = Vector2.Zero;
+    }
+
+    public void OnGetEyeOffset(Entity<CursorOffsetRequiresWieldComponent> entity, ref HeldRelayedEvent<GetEyeOffsetRelayedEvent> args)
+    {
+        if (!TryComp(entity.Owner, out WieldableComponent? wieldableComp))
+            return;
+
+        if (!wieldableComp.Wielded)
+            return;
+
+        var offset = _eyeOffset.OffsetAfterMouse(entity.Owner, null);
+        if (offset == null)
+            return;
+
+        args.Args.Offset += offset.Value;
+    }
+}
diff --git a/Content.Server/Movement/Components/EyeCursorOffsetComponent.cs b/Content.Server/Movement/Components/EyeCursorOffsetComponent.cs
new file mode 100644 (file)
index 0000000..b3809fe
--- /dev/null
@@ -0,0 +1,12 @@
+using System.Numerics;
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Systems;
+using Robust.Shared.GameStates;
+
+namespace Content.Server.Movement.Components;
+
+[RegisterComponent]
+public sealed partial class EyeCursorOffsetComponent : SharedEyeCursorOffsetComponent
+{
+
+}
diff --git a/Content.Server/Wieldable/WieldableSystem.cs b/Content.Server/Wieldable/WieldableSystem.cs
new file mode 100644 (file)
index 0000000..35f7527
--- /dev/null
@@ -0,0 +1,45 @@
+using Content.Server.Movement.Components;
+using Content.Server.Movement.Systems;
+using Content.Shared.Camera;
+using Content.Shared.Hands;
+using Content.Shared.Movement.Components;
+using Content.Shared.Wieldable;
+using Content.Shared.Wieldable.Components;
+
+namespace Content.Server.Wieldable;
+
+public sealed class WieldableSystem : SharedWieldableSystem
+{
+    [Dependency] private readonly ContentEyeSystem _eye = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, ItemUnwieldedEvent>(OnEyeOffsetUnwielded);
+        SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, ItemWieldedEvent>(OnEyeOffsetWielded);
+        SubscribeLocalEvent<CursorOffsetRequiresWieldComponent, HeldRelayedEvent<GetEyePvsScaleRelayedEvent>>(OnGetEyePvsScale);
+    }
+
+    private void OnEyeOffsetUnwielded(Entity<CursorOffsetRequiresWieldComponent> entity, ref ItemUnwieldedEvent args)
+    {
+        _eye.UpdatePvsScale(args.User);
+    }
+
+    private void OnEyeOffsetWielded(Entity<CursorOffsetRequiresWieldComponent> entity, ref ItemWieldedEvent args)
+    {
+        _eye.UpdatePvsScale(args.User);
+    }
+
+    private void OnGetEyePvsScale(Entity<CursorOffsetRequiresWieldComponent> entity,
+        ref HeldRelayedEvent<GetEyePvsScaleRelayedEvent> args)
+    {
+        if (!TryComp(entity, out EyeCursorOffsetComponent? eyeCursorOffset) || !TryComp(entity.Owner, out WieldableComponent? wieldableComp))
+            return;
+
+        if (!wieldableComp.Wielded)
+            return;
+
+        args.Args.Scale += eyeCursorOffset.PvsIncrease;
+    }
+}
index de9c7c9e178fa6a626b6fb3c4f608e13213b111b..0e3c00110a321a5160bdff67a9e5e2aff73221c4 100644 (file)
@@ -1,4 +1,5 @@
 using System.Numerics;
+using Content.Shared.Inventory;
 using Content.Shared.Movement.Systems;
 
 namespace Content.Shared.Camera;
@@ -17,3 +18,15 @@ namespace Content.Shared.Camera;
 /// </remarks>
 [ByRefEvent]
 public record struct GetEyeOffsetEvent(Vector2 Offset);
+
+/// <summary>
+///     Raised on any equipped and in-hand items that may modify the eye offset.
+///     Pockets and suitstorage are excluded.
+/// </summary>
+[ByRefEvent]
+public sealed class GetEyeOffsetRelayedEvent : EntityEventArgs, IInventoryRelayEvent
+{
+    public SlotFlags TargetSlots { get; } = ~(SlotFlags.POCKET & SlotFlags.SUITSTORAGE);
+
+    public Vector2 Offset;
+}
diff --git a/Content.Shared/Camera/GetEyePvsScaleEvent.cs b/Content.Shared/Camera/GetEyePvsScaleEvent.cs
new file mode 100644 (file)
index 0000000..482b755
--- /dev/null
@@ -0,0 +1,33 @@
+using System.Numerics;
+using Content.Shared.Inventory;
+using Content.Shared.Movement.Systems;
+
+namespace Content.Shared.Camera;
+
+/// <summary>
+///     Raised directed by-ref when <see cref="SharedContentEyeSystem.UpdatePvsScale"/> is called.
+///     Should be subscribed to by any systems that want to modify an entity's eye PVS scale,
+///     so that they do not override each other. Keep in mind that this should be done serverside;
+///     the client may set a new PVS scale, but the server won't provide the data if it isn't done on the server.
+/// </summary>
+/// <param name="Scale">
+///     The total scale to apply.
+/// </param>
+/// <remarks>
+///     Note that in most cases <see cref="Scale"/> should be incremented or decremented by subscribers, not set.
+///     Otherwise, any offsets applied by previous subscribing systems will be overridden.
+/// </remarks>
+[ByRefEvent]
+public record struct GetEyePvsScaleEvent(float Scale);
+
+/// <summary>
+///     Raised on any equipped and in-hand items that may modify the eye offset.
+///     Pockets and suitstorage are excluded.
+/// </summary>
+[ByRefEvent]
+public sealed class GetEyePvsScaleRelayedEvent : EntityEventArgs, IInventoryRelayEvent
+{
+    public SlotFlags TargetSlots { get; } = ~(SlotFlags.POCKET & SlotFlags.SUITSTORAGE);
+
+    public float Scale;
+}
index a2ce0e77e20cae6b3569eb575a9ba0674b3accab..a497016c46f014aa46c97db62855d1ffcc1d76b3 100644 (file)
@@ -1,4 +1,6 @@
 using System.Numerics;
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Systems;
 using JetBrains.Annotations;
 using Robust.Shared.Network;
 using Robust.Shared.Serialization;
@@ -28,7 +30,7 @@ public abstract class SharedCameraRecoilSystem : EntitySystem
     /// </summary>
     protected const float KickMagnitudeMax = 1f;
 
-    [Dependency] private readonly SharedEyeSystem _eye = default!;
+    [Dependency] private readonly SharedContentEyeSystem _eye = default!;
     [Dependency] private readonly INetManager _net = default!;
 
     public override void Initialize()
@@ -81,9 +83,7 @@ public abstract class SharedCameraRecoilSystem : EntitySystem
                 continue;
 
             recoil.LastKick = recoil.CurrentKick;
-            var ev = new GetEyeOffsetEvent();
-            RaiseLocalEvent(uid, ref ev);
-            _eye.SetOffset(uid, ev.Offset, eye);
+            _eye.UpdateEyeOffset((uid, eye));
         }
     }
 
index 9e8e0fa744156d0b359a51dfec7412b95111f0c5..a0e02cf2e1ad0e5ee0d1d0b77762322727af64f6 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Camera;
 using Content.Shared.Hands.Components;
 using Content.Shared.Movement.Systems;
 
@@ -7,6 +8,8 @@ public abstract partial class SharedHandsSystem
 {
     private void InitializeRelay()
     {
+        SubscribeLocalEvent<HandsComponent, GetEyeOffsetRelayedEvent>(RelayEvent);
+        SubscribeLocalEvent<HandsComponent, GetEyePvsScaleRelayedEvent>(RelayEvent);
         SubscribeLocalEvent<HandsComponent, RefreshMovementSpeedModifiersEvent>(RelayEvent);
     }
 
diff --git a/Content.Shared/Movement/Components/CursorOffsetRequiresWieldComponent.cs b/Content.Shared/Movement/Components/CursorOffsetRequiresWieldComponent.cs
new file mode 100644 (file)
index 0000000..3f5a128
--- /dev/null
@@ -0,0 +1,13 @@
+using Content.Shared.Wieldable;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Movement.Components;
+
+/// <summary>
+/// Indicates that this item requires wielding for the cursor offset effect to be active.
+/// </summary>
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedWieldableSystem))]
+public sealed partial class CursorOffsetRequiresWieldComponent : Component
+{
+
+}
diff --git a/Content.Shared/Movement/Components/EyeCursorOffsetComponent.cs b/Content.Shared/Movement/Components/EyeCursorOffsetComponent.cs
new file mode 100644 (file)
index 0000000..e088422
--- /dev/null
@@ -0,0 +1,32 @@
+using System.Numerics;
+using Content.Shared.Movement.Systems;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Movement.Components;
+
+/// <summary>
+/// Displaces SS14 eye data when given to an entity.
+/// </summary>
+[ComponentProtoName("EyeCursorOffset"), NetworkedComponent]
+public abstract partial class SharedEyeCursorOffsetComponent : Component
+{
+    /// <summary>
+    /// The amount the view will be displaced when the cursor is positioned at/beyond the max offset distance.
+    /// Measured in tiles.
+    /// </summary>
+    [DataField]
+    public float MaxOffset = 3f;
+
+    /// <summary>
+    /// The speed which the camera adjusts to new positions. 0.5f seems like a good value, but can be changed if you want very slow/instant adjustments.
+    /// </summary>
+    [DataField]
+    public float OffsetSpeed = 0.5f;
+
+    /// <summary>
+    /// The amount the PVS should increase to account for the max offset.
+    /// Should be 1/10 of MaxOffset most of the time.
+    /// </summary>
+    [DataField]
+    public float PvsIncrease = 0.3f;
+}
index faade44c85871d98ebc98fad44635c9b70894f08..71bc65a79ea0ab710d452d68ee64dbc55370d495 100644 (file)
@@ -140,11 +140,29 @@ public abstract class SharedContentEyeSystem : EntitySystem
         Dirty(uid, component);
     }
 
-    public void UpdateEyeOffset(Entity<EyeComponent?> eye)
+    public void UpdateEyeOffset(Entity<EyeComponent> eye)
     {
         var ev = new GetEyeOffsetEvent();
         RaiseLocalEvent(eye, ref ev);
-        _eye.SetOffset(eye, ev.Offset, eye);
+
+        var evRelayed = new GetEyeOffsetRelayedEvent();
+        RaiseLocalEvent(eye, ref evRelayed);
+
+        _eye.SetOffset(eye, ev.Offset + evRelayed.Offset, eye);
+    }
+
+    public void UpdatePvsScale(EntityUid uid, ContentEyeComponent? contentEye = null, EyeComponent? eye = null)
+    {
+        if (!Resolve(uid, ref contentEye) || !Resolve(uid, ref eye))
+            return;
+
+        var ev = new GetEyePvsScaleEvent();
+        RaiseLocalEvent(uid, ref ev);
+
+        var evRelayed = new GetEyePvsScaleRelayedEvent();
+        RaiseLocalEvent(uid, ref evRelayed);
+
+        _eye.SetPvsScale((uid, eye), 1 + ev.Scale + evRelayed.Scale);
     }
 
     /// <summary>
index b322bbe51bce7ef78aab366f575d0b7adb0fd0b5..ffa78ba42a20a2ac7c8d0df338b68c94dacec317 100644 (file)
@@ -6,7 +6,7 @@ namespace Content.Shared.Weapons.Melee.Components;
 /// <summary>
 /// Indicates that this meleeweapon requires wielding to be useable.
 /// </summary>
-[RegisterComponent, NetworkedComponent, Access(typeof(WieldableSystem))]
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedWieldableSystem))]
 public sealed partial class MeleeRequiresWieldComponent : Component
 {
 
index 2016459b9d59f09185dd11eef5b047cef8d4257b..d5016c90e72594b0ae6f1bca8b5d95a67668e3ec 100644 (file)
@@ -7,7 +7,7 @@ namespace Content.Shared.Weapons.Ranged.Components;
 /// Indicates that this gun requires wielding to be useable.
 /// </summary>
 [RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
-[Access(typeof(WieldableSystem))]
+[Access(typeof(SharedWieldableSystem))]
 public sealed partial class GunRequiresWieldComponent : Component
 {
     [DataField, AutoNetworkedField]
index 522319ccbd330a6253790fbb8cf45e6bf0fdd9ad..bd2e9d4dd1e57cad66e268d3a5cfd87973a76f69 100644 (file)
@@ -6,7 +6,7 @@ namespace Content.Shared.Weapons.Ranged.Components;
 /// <summary>
 /// Applies an accuracy bonus upon wielding.
 /// </summary>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(WieldableSystem))]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedWieldableSystem))]
 public sealed partial class GunWieldBonusComponent : Component
 {
     [ViewVariables(VVAccess.ReadWrite), DataField("minAngle"), AutoNetworkedField]
index 3336923b024c8b014003d7b6117da9478fe26bd1..86afe1897b05f6b0fccfd4943fd11e3721063e06 100644 (file)
@@ -2,7 +2,7 @@ using Content.Shared.Damage;
 
 namespace Content.Shared.Wieldable.Components;
 
-[RegisterComponent, Access(typeof(WieldableSystem))]
+[RegisterComponent, Access(typeof(SharedWieldableSystem))]
 public sealed partial class IncreaseDamageOnWieldComponent : Component
 {
     [DataField("damage", required: true)]
index 5dc6abbbbea5edbadbfa08c8a71d051bc8ebf6c3..c146940b7a2c5841f0356e20cbd0c46d0fdc9e90 100644 (file)
@@ -7,7 +7,7 @@ namespace Content.Shared.Wieldable.Components;
 /// <summary>
 ///     Used for objects that can be wielded in two or more hands,
 /// </summary>
-[RegisterComponent, NetworkedComponent, Access(typeof(WieldableSystem)), AutoGenerateComponentState]
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedWieldableSystem)), AutoGenerateComponentState]
 public sealed partial class WieldableComponent : Component
 {
     [DataField("wieldSound")]
similarity index 99%
rename from Content.Shared/Wieldable/WieldableSystem.cs
rename to Content.Shared/Wieldable/SharedWieldableSystem.cs
index 200a50d28f73e0aebb176c1f4a3d40fc814ae104..24c63c5f2f1370c2eab7d16750f90a80d1193cf4 100644 (file)
@@ -1,4 +1,5 @@
 using System.Linq;
+using Content.Shared.Camera;
 using Content.Shared.Examine;
 using Content.Shared.Hands;
 using Content.Shared.Hands.Components;
@@ -7,6 +8,7 @@ using Content.Shared.IdentityManagement;
 using Content.Shared.Interaction.Events;
 using Content.Shared.Inventory.VirtualItem;
 using Content.Shared.Item;
+using Content.Shared.Movement.Components;
 using Content.Shared.Popups;
 using Content.Shared.Timing;
 using Content.Shared.Verbs;
@@ -23,7 +25,7 @@ using Robust.Shared.Timing;
 
 namespace Content.Shared.Wieldable;
 
-public sealed class WieldableSystem : EntitySystem
+public abstract class SharedWieldableSystem : EntitySystem
 {
     [Dependency] private readonly IGameTiming _timing = default!;
     [Dependency] private readonly INetManager _netManager = default!;
index 4ea0061c96149941c4ab1d49cf9c448cde59ae8b..cca3a6f30215ce16732a94f38a6b74991f0bb129 100644 (file)
       - CartridgeAntiMateriel
     capacity: 5
     proto: CartridgeAntiMateriel
+  - type: CursorOffsetRequiresWield
+  - type: EyeCursorOffset
+    maxOffset: 3
+    pvsIncrease: 0.3
 
 - type: entity
   name: musket