]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Sprite Movement working with AI movement (#33494)
authorEd <96445749+TheShuEd@users.noreply.github.com>
Wed, 18 Dec 2024 16:15:34 +0000 (19:15 +0300)
committerGitHub <noreply@github.com>
Wed, 18 Dec 2024 16:15:34 +0000 (17:15 +0100)
* FINALLY

* Update animals.yml

Content.Client/Movement/Systems/ClientSpriteMovementSystem.cs [new file with mode: 0644]
Content.Client/Movement/Systems/SpriteMovementSystem.cs [deleted file]
Content.Server/Movement/Systems/SpriteMovementSystem.cs [new file with mode: 0644]
Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs
Content.Server/NPC/Systems/NPCSteeringSystem.cs
Content.Shared/Movement/Components/SpriteMovementComponent.cs
Content.Shared/Movement/Events/SpriteMoveEvent.cs [new file with mode: 0644]
Content.Shared/Movement/Systems/SharedMoverController.Input.cs
Content.Shared/Movement/Systems/SharedSpriteMovementSystem.cs [new file with mode: 0644]
Resources/Prototypes/Entities/Mobs/NPCs/animals.yml

diff --git a/Content.Client/Movement/Systems/ClientSpriteMovementSystem.cs b/Content.Client/Movement/Systems/ClientSpriteMovementSystem.cs
new file mode 100644 (file)
index 0000000..1700796
--- /dev/null
@@ -0,0 +1,46 @@
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Systems;
+using Robust.Client.GameObjects;
+using Robust.Shared.Timing;
+
+namespace Content.Client.Movement.Systems;
+
+/// <summary>
+/// Controls the switching of motion and standing still animation
+/// </summary>
+public sealed class ClientSpriteMovementSystem : SharedSpriteMovementSystem
+{
+    [Dependency] private readonly IGameTiming _timing = default!;
+
+    private EntityQuery<SpriteComponent> _spriteQuery;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        _spriteQuery = GetEntityQuery<SpriteComponent>();
+
+        SubscribeLocalEvent<SpriteMovementComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
+    }
+
+    private void OnAfterAutoHandleState(Entity<SpriteMovementComponent> ent, ref AfterAutoHandleStateEvent args)
+    {
+        if (!_spriteQuery.TryGetComponent(ent, out var sprite))
+            return;
+
+        if (ent.Comp.IsMoving)
+        {
+            foreach (var (layer, state) in ent.Comp.MovementLayers)
+            {
+                sprite.LayerSetData(layer, state);
+            }
+        }
+        else
+        {
+            foreach (var (layer, state) in ent.Comp.NoMovementLayers)
+            {
+                sprite.LayerSetData(layer, state);
+            }
+        }
+    }
+}
diff --git a/Content.Client/Movement/Systems/SpriteMovementSystem.cs b/Content.Client/Movement/Systems/SpriteMovementSystem.cs
deleted file mode 100644 (file)
index b620353..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-using Content.Shared.Movement.Components;
-using Content.Shared.Movement.Events;
-using Content.Shared.Movement.Systems;
-using Robust.Client.GameObjects;
-using Robust.Shared.Timing;
-
-namespace Content.Client.Movement.Systems;
-
-/// <summary>
-/// Handles setting sprite states based on whether an entity has movement input.
-/// </summary>
-public sealed class SpriteMovementSystem : EntitySystem
-{
-    [Dependency] private readonly IGameTiming _timing = default!;
-
-    private EntityQuery<SpriteComponent> _spriteQuery;
-
-    public override void Initialize()
-    {
-        base.Initialize();
-        SubscribeLocalEvent<SpriteMovementComponent, MoveInputEvent>(OnSpriteMoveInput);
-        _spriteQuery = GetEntityQuery<SpriteComponent>();
-    }
-
-    private void OnSpriteMoveInput(EntityUid uid, SpriteMovementComponent component, ref MoveInputEvent args)
-    {
-        if (!_timing.IsFirstTimePredicted)
-            return;
-
-        var oldMoving = (SharedMoverController.GetNormalizedMovement(args.OldMovement) & MoveButtons.AnyDirection) != MoveButtons.None;
-        var moving = (SharedMoverController.GetNormalizedMovement(args.Entity.Comp.HeldMoveButtons) & MoveButtons.AnyDirection) != MoveButtons.None;
-
-        if (oldMoving == moving || !_spriteQuery.TryGetComponent(uid, out var sprite))
-            return;
-
-        if (moving)
-        {
-            foreach (var (layer, state) in component.MovementLayers)
-            {
-                sprite.LayerSetData(layer, state);
-            }
-        }
-        else
-        {
-            foreach (var (layer, state) in component.NoMovementLayers)
-            {
-                sprite.LayerSetData(layer, state);
-            }
-        }
-    }
-}
diff --git a/Content.Server/Movement/Systems/SpriteMovementSystem.cs b/Content.Server/Movement/Systems/SpriteMovementSystem.cs
new file mode 100644 (file)
index 0000000..9fc4d82
--- /dev/null
@@ -0,0 +1,7 @@
+using Content.Shared.Movement.Systems;
+
+namespace Content.Server.Movement.Systems;
+
+public sealed class SpriteMovementSystem : SharedSpriteMovementSystem
+{
+}
index fa43b3e7524b59300a297973a7452e6fd5d474c0..6a295198c2572e3c769cdbca5e155c42b9b15798 100644 (file)
@@ -253,7 +253,7 @@ public sealed partial class NPCSteeringSystem
 
                 if (!targetCoordinates.IsValid(EntityManager))
                 {
-                    SetDirection(mover, steering, Vector2.Zero);
+                    SetDirection(uid, mover, steering, Vector2.Zero);
                     steering.Status = SteeringStatus.NoPath;
                     return false;
                 }
@@ -263,7 +263,7 @@ public sealed partial class NPCSteeringSystem
                 // Can't make it again.
                 if (ourMap.MapId != targetMap.MapId)
                 {
-                    SetDirection(mover, steering, Vector2.Zero);
+                    SetDirection(uid, mover, steering, Vector2.Zero);
                     steering.Status = SteeringStatus.NoPath;
                     return false;
                 }
index fc63d1e6156a5d9f2a1fe72f878b28048b999ecb..a8124c02493a5f021db26189097f0278df0cb24c 100644 (file)
@@ -11,6 +11,7 @@ using Content.Shared.Climbing.Systems;
 using Content.Shared.CombatMode;
 using Content.Shared.Interaction;
 using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Events;
 using Content.Shared.Movement.Systems;
 using Content.Shared.NPC;
 using Content.Shared.NPC.Components;
@@ -207,6 +208,9 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
         if (EntityManager.TryGetComponent(uid, out InputMoverComponent? controller))
         {
             controller.CurTickSprintMovement = Vector2.Zero;
+
+            var ev = new SpriteMoveEvent(false);
+            RaiseLocalEvent(uid, ref ev);
         }
 
         component.PathfindToken?.Cancel();
@@ -270,7 +274,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
         }
     }
 
-    private void SetDirection(InputMoverComponent component, NPCSteeringComponent steering, Vector2 value, bool clear = true)
+    private void SetDirection(EntityUid uid, InputMoverComponent component, NPCSteeringComponent steering, Vector2 value, bool clear = true)
     {
         if (clear && value.Equals(Vector2.Zero))
         {
@@ -282,6 +286,9 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
         component.CurTickSprintMovement = value;
         component.LastInputTick = _timing.CurTick;
         component.LastInputSubTick = ushort.MaxValue;
+
+        var ev = new SpriteMoveEvent(true);
+        RaiseLocalEvent(uid, ref ev);
     }
 
     /// <summary>
@@ -297,7 +304,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
     {
         if (Deleted(steering.Coordinates.EntityId))
         {
-            SetDirection(mover, steering, Vector2.Zero);
+            SetDirection(uid, mover, steering, Vector2.Zero);
             steering.Status = SteeringStatus.NoPath;
             return;
         }
@@ -305,14 +312,14 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
         // No path set from pathfinding or the likes.
         if (steering.Status == SteeringStatus.NoPath)
         {
-            SetDirection(mover, steering, Vector2.Zero);
+            SetDirection(uid, mover, steering, Vector2.Zero);
             return;
         }
 
         // Can't move at all, just noop input.
         if (!mover.CanMove)
         {
-            SetDirection(mover, steering, Vector2.Zero);
+            SetDirection(uid, mover, steering, Vector2.Zero);
             steering.Status = SteeringStatus.NoPath;
             return;
         }
@@ -341,7 +348,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
 
         if (steering.CanSeek && !TrySeek(uid, mover, steering, body, xform, offsetRot, moveSpeed, interest, frameTime, ref forceSteer))
         {
-            SetDirection(mover, steering, Vector2.Zero);
+            SetDirection(uid, mover, steering, Vector2.Zero);
             return;
         }
 
@@ -354,7 +361,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
 
         if (!forceSteer)
         {
-            SetDirection(mover, steering, steering.LastSteerDirection, false);
+            SetDirection(uid, mover, steering, steering.LastSteerDirection, false);
             return;
         }
 
@@ -391,7 +398,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
 
         steering.LastSteerDirection = resultDirection;
         DebugTools.Assert(!float.IsNaN(resultDirection.X));
-        SetDirection(mover, steering, resultDirection, false);
+        SetDirection(uid, mover, steering, resultDirection, false);
     }
 
     private EntityCoordinates GetCoordinates(PathPoly poly)
index 8dd058f15446a8c640c9477b83d6381179caabb4..b5a9e373521521f27def04b3ae4cd64cb79e5170 100644 (file)
@@ -5,7 +5,7 @@ namespace Content.Shared.Movement.Components;
 /// <summary>
 /// Updates a sprite layer based on whether an entity is moving via input or not.
 /// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
 public sealed partial class SpriteMovementComponent : Component
 {
     /// <summary>
@@ -19,4 +19,7 @@ public sealed partial class SpriteMovementComponent : Component
     /// </summary>
     [DataField]
     public Dictionary<string, PrototypeLayerData> NoMovementLayers = new();
+
+    [DataField, AutoNetworkedField]
+    public bool IsMoving;
 }
diff --git a/Content.Shared/Movement/Events/SpriteMoveEvent.cs b/Content.Shared/Movement/Events/SpriteMoveEvent.cs
new file mode 100644 (file)
index 0000000..25ebffe
--- /dev/null
@@ -0,0 +1,15 @@
+namespace Content.Shared.Movement.Events;
+
+/// <summary>
+/// Raised on an entity whenever it should change movement sprite
+/// </summary>
+[ByRefEvent]
+public readonly struct SpriteMoveEvent
+{
+    public readonly bool IsMoving = false;
+
+    public SpriteMoveEvent(bool isMoving)
+    {
+        IsMoving = isMoving;
+    }
+}
index 1fe38b6cdf1b6cc5fe7fe6045bb47dc701a43863..6f508d9038c0fea7e93e85b96f326ebf66f38f58 100644 (file)
@@ -96,6 +96,9 @@ namespace Content.Shared.Movement.Systems
             entity.Comp.HeldMoveButtons = buttons;
             RaiseLocalEvent(entity, ref moveEvent);
             Dirty(entity, entity.Comp);
+
+            var ev = new SpriteMoveEvent(entity.Comp.HeldMoveButtons != MoveButtons.None);
+            RaiseLocalEvent(entity, ref ev);
         }
 
         private void OnMoverHandleState(Entity<InputMoverComponent> entity, ref ComponentHandleState args)
@@ -119,6 +122,9 @@ namespace Content.Shared.Movement.Systems
                 var moveEvent = new MoveInputEvent(entity, entity.Comp.HeldMoveButtons);
                 entity.Comp.HeldMoveButtons = state.HeldMoveButtons;
                 RaiseLocalEvent(entity.Owner, ref moveEvent);
+
+                var ev = new SpriteMoveEvent(entity.Comp.HeldMoveButtons != MoveButtons.None);
+                RaiseLocalEvent(entity, ref ev);
             }
         }
 
diff --git a/Content.Shared/Movement/Systems/SharedSpriteMovementSystem.cs b/Content.Shared/Movement/Systems/SharedSpriteMovementSystem.cs
new file mode 100644 (file)
index 0000000..eb4bbc1
--- /dev/null
@@ -0,0 +1,23 @@
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Events;
+
+namespace Content.Shared.Movement.Systems;
+
+public abstract class SharedSpriteMovementSystem : EntitySystem
+{
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<SpriteMovementComponent, SpriteMoveEvent>(OnSpriteMoveInput);
+    }
+
+    private void OnSpriteMoveInput(Entity<SpriteMovementComponent> ent, ref SpriteMoveEvent args)
+    {
+        if (ent.Comp.IsMoving == args.IsMoving)
+            return;
+
+        ent.Comp.IsMoving = args.IsMoving;
+        Dirty(ent);
+    }
+}
index d801530c6bc5c7467af08470ebd81880c6be325f..b776a156fed5f35c0edf61c46b33a401590d6aa7 100644 (file)
 # Code unique spider prototypes or combine them all into one spider and get a
 # random sprite state when you spawn it.
 - type: entity
-  name: tarantula
   parent: [ SimpleMobBase, MobCombat ]
-  id: MobGiantSpider
-  description: Widely recognized to be the literal worst thing in existence.
+  id: MobSpiderBase
+  abstract: true
   components:
-  - type: Sprite
-    drawdepth: Mobs
-    layers:
-    - map: ["enum.DamageStateVisualLayers.Base", "movement"]
-      state: tarantula
-      sprite: Mobs/Animals/spider.rsi
-  - type: SpriteMovement
-    movementLayers:
-      movement:
-        state: tarantula-moving
-    noMovementLayers:
-      movement:
-        state: tarantula
   - type: Physics
   - type: Fixtures
     fixtures:
         - MobMask
         layer:
         - MobLayer
-  - type: DamageStateVisuals
-    states:
-      Alive:
-        Base: tarantula
-      Critical:
-        Base: tarantula_dead
-      Dead:
-        Base: tarantula_dead
   - type: Butcherable
     spawned:
     - id: FoodMeatSpider
     thresholds:
       0: Alive
       90: Dead
-  - type: MeleeWeapon
-    altDisarm: false
-    angle: 0
-    animation: WeaponArcBite
-    soundHit:
-      path: /Audio/Effects/bite.ogg
-    damage:
-      types:
-        Piercing: 6
   - type: SolutionContainerManager
     solutions:
       melee:
         Brute: -0.07
         Burn: -0.07
 
+- type: entity
+  parent: MobSpiderBase
+  id: MobSpiderAngryBase
+  abstract: true
+  components:
+  - type: NpcFactionMember
+    factions:
+      - Xeno
+  - type: InputMover
+  - type: MobMover
+  - type: HTN
+    rootTask:
+      task: SimpleHostileCompound
+  - type: GhostRole
+    makeSentient: true
+    name: ghost-role-information-giant-spider-name
+    description: ghost-role-information-giant-spider-description
+    rules: ghost-role-information-giant-spider-rules
+    raffle:
+      settings: short
+  - type: GhostTakeoverAvailable
+
 - type: entity
   name: tarantula
-  parent: MobGiantSpider
-  id: MobGiantSpiderAngry
-  suffix: Angry
+  parent: MobSpiderBase
+  id: MobGiantSpider
+  description: Widely recognized to be the literal worst thing in existence.
   components:
-    - type: NpcFactionMember
-      factions:
-        - Xeno
-    - type: InputMover
-    - type: MobMover
-    - type: HTN
-      rootTask:
-        task: SimpleHostileCompound
-    - type: GhostRole
-      makeSentient: true
-      name: ghost-role-information-giant-spider-name
-      description: ghost-role-information-giant-spider-description
-      rules: ghost-role-information-giant-spider-rules
-      raffle:
-        settings: short
-    - type: GhostTakeoverAvailable
+  - type: Sprite
+    drawdepth: Mobs
+    layers:
+    - map: ["enum.DamageStateVisualLayers.Base", "movement"]
+      state: tarantula
+      sprite: Mobs/Animals/spider.rsi
+  - type: SpriteMovement
+    movementLayers:
+      movement:
+        state: tarantula-moving
+    noMovementLayers:
+      movement:
+        state: tarantula
+  - type: DamageStateVisuals
+    states:
+      Alive:
+        Base: tarantula
+      Critical:
+        Base: tarantula_dead
+      Dead:
+        Base: tarantula_dead
+  - type: MeleeWeapon
+    altDisarm: false
+    angle: 0
+    animation: WeaponArcBite
+    soundHit:
+      path: /Audio/Effects/bite.ogg
+    damage:
+      types:
+        Piercing: 6
+
+- type: entity
+  parent:
+  - MobGiantSpider
+  - MobSpiderAngryBase
+  id: MobGiantSpiderAngry
 
 - type: entity
   name: clown spider
-  parent: MobGiantSpiderAngry
+  parent: MobSpiderAngryBase
   id: MobClownSpider
   description: Combines the two most terrifying things in existence, spiders and clowns.
   components: