From 9a40cf81f55722083a985e4cdddda9c6008beb08 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Mon, 25 Dec 2023 18:34:21 +1100 Subject: [PATCH] Add sprite movement states (#22940) * Add sprite movement states Did it for borgs for reference for future implementations. * Fix * Fix prediction issue * review --- .../Movement/Systems/SpriteMovementSystem.cs | 51 +++++++++++ .../Components/InputMoverComponent.cs | 26 ++++-- .../Components/SpriteMovementComponent.cs | 22 +++++ .../Movement/Events/MoveInputEvent.cs | 11 ++- .../Systems/SharedMoverController.Input.cs | 84 ++++++++++++++---- .../Entities/Mobs/Cyborgs/borg_chassis.yml | 24 +++++ .../Mobs/Silicon/chassis.rsi/janitor.png | Bin 4280 -> 3084 bytes .../Silicon/chassis.rsi/janitor_moving.png | Bin 0 -> 4280 bytes .../Mobs/Silicon/chassis.rsi/medical.png | Bin 3342 -> 3198 bytes .../Silicon/chassis.rsi/medical_moving.png | Bin 0 -> 3342 bytes .../Mobs/Silicon/chassis.rsi/meta.json | 34 +++++++ .../Mobs/Silicon/chassis.rsi/miner.png | Bin 2958 -> 2203 bytes .../Mobs/Silicon/chassis.rsi/miner_moving.png | Bin 0 -> 2958 bytes 13 files changed, 227 insertions(+), 25 deletions(-) create mode 100644 Content.Client/Movement/Systems/SpriteMovementSystem.cs create mode 100644 Content.Shared/Movement/Components/SpriteMovementComponent.cs create mode 100644 Resources/Textures/Mobs/Silicon/chassis.rsi/janitor_moving.png create mode 100644 Resources/Textures/Mobs/Silicon/chassis.rsi/medical_moving.png create mode 100644 Resources/Textures/Mobs/Silicon/chassis.rsi/miner_moving.png diff --git a/Content.Client/Movement/Systems/SpriteMovementSystem.cs b/Content.Client/Movement/Systems/SpriteMovementSystem.cs new file mode 100644 index 0000000000..37045c5f0d --- /dev/null +++ b/Content.Client/Movement/Systems/SpriteMovementSystem.cs @@ -0,0 +1,51 @@ +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; + +/// +/// Handles setting sprite states based on whether an entity has movement input. +/// +public sealed class SpriteMovementSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + + private EntityQuery _spriteQuery; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnSpriteMoveInput); + _spriteQuery = GetEntityQuery(); + } + + private void OnSpriteMoveInput(EntityUid uid, SpriteMovementComponent component, ref MoveInputEvent args) + { + if (!_timing.IsFirstTimePredicted) + return; + + var oldMoving = SharedMoverController.GetNormalizedMovement(args.OldMovement) != MoveButtons.None; + var moving = SharedMoverController.GetNormalizedMovement(args.Component.HeldMoveButtons) != 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.Shared/Movement/Components/InputMoverComponent.cs b/Content.Shared/Movement/Components/InputMoverComponent.cs index 5562bfaee4..f1e34c90df 100644 --- a/Content.Shared/Movement/Components/InputMoverComponent.cs +++ b/Content.Shared/Movement/Components/InputMoverComponent.cs @@ -1,12 +1,13 @@ using System.Numerics; using Content.Shared.Movement.Systems; using Robust.Shared.GameStates; +using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Timing; namespace Content.Shared.Movement.Components { - [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] + [RegisterComponent, NetworkedComponent] public sealed partial class InputMoverComponent : Component { // This class has to be able to handle server TPS being lower than client FPS. @@ -40,32 +41,30 @@ namespace Content.Shared.Movement.Components public Vector2 CurTickWalkMovement; public Vector2 CurTickSprintMovement; - [AutoNetworkedField] public MoveButtons HeldMoveButtons = MoveButtons.None; /// /// Entity our movement is relative to. /// - [AutoNetworkedField] public EntityUid? RelativeEntity; /// /// Although our movement might be relative to a particular entity we may have an additional relative rotation /// e.g. if we've snapped to a different cardinal direction /// - [ViewVariables, AutoNetworkedField] + [ViewVariables] public Angle TargetRelativeRotation = Angle.Zero; /// /// The current relative rotation. This will lerp towards the . /// - [ViewVariables, AutoNetworkedField] + [ViewVariables] public Angle RelativeRotation; /// /// If we traverse on / off a grid then set a timer to update our relative inputs. /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] [ViewVariables(VVAccess.ReadWrite)] public TimeSpan LerpTarget; @@ -73,7 +72,18 @@ namespace Content.Shared.Movement.Components public bool Sprinting => (HeldMoveButtons & MoveButtons.Walk) == 0x0; - [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public bool CanMove { get; set; } = true; + [ViewVariables(VVAccess.ReadWrite)] + public bool CanMove = true; + } + + [Serializable, NetSerializable] + public sealed class InputMoverComponentState : ComponentState + { + public MoveButtons HeldMoveButtons; + public NetEntity? RelativeEntity; + public Angle TargetRelativeRotation; + public Angle RelativeRotation; + public TimeSpan LerpTarget; + public bool CanMove; } } diff --git a/Content.Shared/Movement/Components/SpriteMovementComponent.cs b/Content.Shared/Movement/Components/SpriteMovementComponent.cs new file mode 100644 index 0000000000..8dd058f154 --- /dev/null +++ b/Content.Shared/Movement/Components/SpriteMovementComponent.cs @@ -0,0 +1,22 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Movement.Components; + +/// +/// Updates a sprite layer based on whether an entity is moving via input or not. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class SpriteMovementComponent : Component +{ + /// + /// Layer and sprite state to use when moving. + /// + [DataField] + public Dictionary MovementLayers = new(); + + /// + /// Layer and sprite state to use when not moving. + /// + [DataField] + public Dictionary NoMovementLayers = new(); +} diff --git a/Content.Shared/Movement/Events/MoveInputEvent.cs b/Content.Shared/Movement/Events/MoveInputEvent.cs index 89e5636acd..2d0f07e6c0 100644 --- a/Content.Shared/Movement/Events/MoveInputEvent.cs +++ b/Content.Shared/Movement/Events/MoveInputEvent.cs @@ -1,15 +1,22 @@ +using Content.Shared.Movement.Components; +using Content.Shared.Movement.Systems; + namespace Content.Shared.Movement.Events; /// -/// Raised on an entity whenever it has a movement input. +/// Raised on an entity whenever it has a movement input change. /// [ByRefEvent] public readonly struct MoveInputEvent { public readonly EntityUid Entity; + public readonly InputMoverComponent Component; + public readonly MoveButtons OldMovement; - public MoveInputEvent(EntityUid entity) + public MoveInputEvent(EntityUid entity, InputMoverComponent component, MoveButtons oldMovement) { Entity = entity; + Component = component; + OldMovement = oldMovement; } } diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs index 1d323a9187..dde4ac063b 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs @@ -4,6 +4,7 @@ using Content.Shared.Follower.Components; using Content.Shared.Input; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; +using Robust.Shared.GameStates; using Robust.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.Player; @@ -48,7 +49,8 @@ namespace Content.Shared.Movement.Systems .Register(); SubscribeLocalEvent(OnInputInit); - SubscribeLocalEvent(OnInputHandleState); + SubscribeLocalEvent(OnMoverGetState); + SubscribeLocalEvent(OnMoverHandleState); SubscribeLocalEvent(OnInputParentChange); SubscribeLocalEvent(OnAutoParentChange); @@ -64,19 +66,76 @@ namespace Content.Shared.Movement.Systems CameraRotationLocked = obj; } + /// + /// Gets the buttons held with opposites cancelled out. + /// + public static MoveButtons GetNormalizedMovement(MoveButtons buttons) + { + var oldMovement = buttons; + + if ((oldMovement & (MoveButtons.Left | MoveButtons.Right)) == (MoveButtons.Left | MoveButtons.Right)) + { + oldMovement &= ~MoveButtons.Left; + oldMovement &= ~MoveButtons.Right; + } + + if ((oldMovement & (MoveButtons.Up | MoveButtons.Down)) == (MoveButtons.Up | MoveButtons.Down)) + { + oldMovement &= ~MoveButtons.Up; + oldMovement &= ~MoveButtons.Down; + } + + return oldMovement; + } + protected void SetMoveInput(InputMoverComponent component, MoveButtons buttons) { if (component.HeldMoveButtons == buttons) return; + // Relay the fact we had any movement event. + // TODO: Ideally we'd do these in a tick instead of out of sim. + var moveEvent = new MoveInputEvent(component.Owner, component, component.HeldMoveButtons); component.HeldMoveButtons = buttons; - Dirty(component); + RaiseLocalEvent(component.Owner, ref moveEvent); + Dirty(component.Owner, component); } - private void OnInputHandleState(EntityUid uid, InputMoverComponent component, ref AfterAutoHandleStateEvent args) + private void OnMoverHandleState(EntityUid uid, InputMoverComponent component, ComponentHandleState args) { + if (args.Current is not InputMoverComponentState state) + return; + + // Handle state + component.LerpTarget = state.LerpTarget; + component.RelativeRotation = state.RelativeRotation; + component.TargetRelativeRotation = state.TargetRelativeRotation; + component.CanMove = state.CanMove; + component.RelativeEntity = EnsureEntity(state.RelativeEntity, uid); + + // Reset component.LastInputTick = GameTick.Zero; component.LastInputSubTick = 0; + + if (component.HeldMoveButtons != state.HeldMoveButtons) + { + var moveEvent = new MoveInputEvent(uid, component, component.HeldMoveButtons); + component.HeldMoveButtons = state.HeldMoveButtons; + RaiseLocalEvent(uid, ref moveEvent); + } + } + + private void OnMoverGetState(EntityUid uid, InputMoverComponent component, ref ComponentGetState args) + { + args.State = new InputMoverComponentState() + { + CanMove = component.CanMove, + RelativeEntity = GetNetEntity(component.RelativeEntity), + LerpTarget = component.LerpTarget, + HeldMoveButtons = component.HeldMoveButtons, + RelativeRotation = component.RelativeRotation, + TargetRelativeRotation = component.TargetRelativeRotation, + }; } private void ShutdownInput() @@ -260,11 +319,6 @@ namespace Content.Shared.Movement.Systems if (!MoverQuery.TryGetComponent(entity, out var moverComp)) return; - // Relay the fact we had any movement event. - // TODO: Ideally we'd do these in a tick instead of out of sim. - var moveEvent = new MoveInputEvent(entity); - RaiseLocalEvent(entity, ref moveEvent); - // For stuff like "Moving out of locker" or the likes // We'll relay a movement input to the parent. if (_container.IsEntityInContainer(entity) && @@ -276,7 +330,7 @@ namespace Content.Shared.Movement.Systems RaiseLocalEvent(xform.ParentUid, ref relayMoveEvent); } - SetVelocityDirection(moverComp, dir, subTick, state); + SetVelocityDirection(entity, moverComp, dir, subTick, state); } private void OnInputInit(EntityUid uid, InputMoverComponent component, ComponentInit args) @@ -308,7 +362,7 @@ namespace Content.Shared.Movement.Systems if (moverComp == null) return; - SetSprinting(moverComp, subTick, walking); + SetSprinting(uid, moverComp, subTick, walking); } public (Vector2 Walking, Vector2 Sprinting) GetVelocityInput(InputMoverComponent mover) @@ -359,7 +413,7 @@ namespace Content.Shared.Movement.Systems /// composed into a single direction vector, . Enabling /// opposite directions will cancel each other out, resulting in no direction. /// - public void SetVelocityDirection(InputMoverComponent component, Direction direction, ushort subTick, bool enabled) + public void SetVelocityDirection(EntityUid entity, InputMoverComponent component, Direction direction, ushort subTick, bool enabled) { // Logger.Info($"[{_gameTiming.CurTick}/{subTick}] {direction}: {enabled}"); @@ -372,10 +426,10 @@ namespace Content.Shared.Movement.Systems _ => throw new ArgumentException(nameof(direction)) }; - SetMoveInput(component, subTick, enabled, bit); + SetMoveInput(entity, component, subTick, enabled, bit); } - private void SetMoveInput(InputMoverComponent component, ushort subTick, bool enabled, MoveButtons bit) + private void SetMoveInput(EntityUid entity, InputMoverComponent component, ushort subTick, bool enabled, MoveButtons bit) { // Modifies held state of a movement button at a certain sub tick and updates current tick movement vectors. ResetSubtick(component); @@ -415,11 +469,11 @@ namespace Content.Shared.Movement.Systems component.LastInputSubTick = 0; } - public void SetSprinting(InputMoverComponent component, ushort subTick, bool walking) + public void SetSprinting(EntityUid entity, InputMoverComponent component, ushort subTick, bool walking) { // Logger.Info($"[{_gameTiming.CurTick}/{subTick}] Sprint: {enabled}"); - SetMoveInput(component, subTick, walking, MoveButtons.Walk); + SetMoveInput(entity, component, subTick, walking, MoveButtons.Walk); } /// diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml index eb6673fea2..4a45717b79 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml @@ -33,6 +33,7 @@ - type: Sprite layers: - state: miner + map: ["movement"] - state: miner_e_r map: ["enum.BorgVisualLayers.Light"] shader: unshaded @@ -41,6 +42,13 @@ shader: unshaded map: ["light"] visible: false + - type: SpriteMovement + movementLayers: + movement: + state: miner_moving + noMovementLayers: + movement: + state: miner - type: BorgChassis maxModules: 4 moduleWhitelist: @@ -119,6 +127,7 @@ - type: Sprite layers: - state: janitor + map: ["movement"] - state: janitor_e_r map: ["enum.BorgVisualLayers.Light"] shader: unshaded @@ -127,6 +136,13 @@ shader: unshaded map: ["light"] visible: false + - type: SpriteMovement + movementLayers: + movement: + state: janitor_moving + noMovementLayers: + movement: + state: janitor - type: BorgChassis maxModules: 4 moduleWhitelist: @@ -162,6 +178,7 @@ - type: Sprite layers: - state: medical + map: ["movement"] - state: medical_e_r map: ["enum.BorgVisualLayers.Light"] shader: unshaded @@ -170,6 +187,13 @@ shader: unshaded map: ["light"] visible: false + - type: SpriteMovement + movementLayers: + movement: + state: medical_moving + noMovementLayers: + movement: + state: medical - type: BorgChassis maxModules: 4 moduleWhitelist: diff --git a/Resources/Textures/Mobs/Silicon/chassis.rsi/janitor.png b/Resources/Textures/Mobs/Silicon/chassis.rsi/janitor.png index ff7d4eb483ab447cc836098870e3e609af530e1b..83275f949bfca7c12002f3848f8af20f2888fbdc 100644 GIT binary patch literal 3084 zcmV+n4D<7eP))OK{7GC1udEFB#xPNhxa0)#Chj%XnyDJ0?1R;&)PdvqTX40DRD4+3vUfm<7r zxCbCYf9=O40E|D9_8=SnL)%g6op_PPj~zn|^+z}#_wCd{U1yHcBkCDtX$VEo?F0Jg z1N3|9r~Q~mfNr!cc%FZ5_~;%U9heeB4YA*KqnE}d#8V^HQ|{G#&XfCh|IxyE{jndD z07^+}iTCk+7UfYc`Yhe&Gw1!OKnGP<{ftu5eKdFO zm*{ZqVM3ku;5n?=gPjJ(i$7dP^{=1hq0RICD$yim`p3^-a}<=t7}FGW*1zvWww*3z zP{$gD5!;U_fNH>SlLx-@-8HnYX0J_L(f|7cHQB zv$JV(L7B?Srd6xf(D`%c*e6*Si@*5{U!&QNIs!1~fdvZ|vk{=Pv)v|(cL3}Nk|t&M z?%liIY%jwp13~S$003olF1u;A~H#bpw)Y|NEB7_K_lh=C_iycUVs385mVro6r z_r@h6d~oS9Em^eCPDfj@ilCDR+Ap*)p-UG#$$#Pmr=h2>(__@#ea5bbw79r9s`>3c z%1lc(MNs8aGqNIz;1D1jdH1k~5dZZR(bTmURWGbl_uEujjYAy04H*&9L~xTAfPAp6 zlSyIz`_fY=pa|>WG_~kqaTcL;gcHFQ0LJke3r7%4@j2DDFMAoljOD8GhFc_>4c818mjJ?uNW5%c;RPrgWXO=oHL%n5X%7pug3~k8lDHo3XFh!(Y?+LdJGsrLzJHwF+`e9UvYEUP z&OX|1{N-1<47R(1udLu_QwS5eU;jPZ|8(mC>bXo@Cl>p*0B~A2jw^r$&=3fz|7|?W z$UXAjRAqGXxZ>w71EF;C(d-LBDf8soMsNGuiTY#T761w5b*3_YZFKuxSI;sP&TF-l zq3~tg_@F z>2u2mB*LbjY-RHD8C=dM0EqwTA#$JxIZNA6% z!GQwbA@P9*EsU_49y2QiNoW| zEr2hv@~KMCM_aM(2v%9HD~B)ukQY0EJ6`}_adrT{M-#zQ0NHwU@~1mO%5cvEX}$?m zytJ5-#@Y|OqF7guo zf^GPKkeCEc-6FhDkjVamla~k%0r1HgJ&y`#7%wvwRerUi9;0zr<8AVC7y>Z@!{~c6 z#b`i}U@8DDfuNlyB1Aen1lw5Xg#4Mm|JBh3$ioI~Vx7ScuM2 zB_)Q4Fk||(uxkK%X7|qRhLEqQsEAYRi-ES#gCMWR0w5LwAs>HnEBSXWqMT`DkIwdh z>9_EJFgR0?XjTpVEUu$>>Pq$Ywb52r&i@GckEfLKGYmJpa=*RZRa91lh_GqX1_MMy z1U0XXa3Ua2C!d}*(I_ol6+*tGxP*5AEP|g~YlgbulmEmf7D1*W&KAfh1t%{!;sQ`6 zKFN&mg1iJI_47Y0Q1=)Ra^H;=5CB4niUYpO$p#{ES`?&CEM5s>C4kGeW} zY1_U1;d}smy3KkPf3Z7Bpj0oX2W1>1K*CxGFNunoX=Yp=i;e*KAE80@Ll3Nf>3&Yv z-w3fl!Epe+h{fkn-BEgWaSxv>P|K!6RHPMBCB3%wZ@d_z&YtRDa~o(&dLP4Hwm;Yw zQt%0oASrer_>8$V1OU@PM3Cq$90C#9 zTFsuXahs)->_zOD>_n&|LYi&)xh=J(*!J`u#af~Fw$zmc5S*|!xZw~0jp*b7G&p)p z5-)bL literal 4280 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 Ca&4>t diff --git a/Resources/Textures/Mobs/Silicon/chassis.rsi/janitor_moving.png b/Resources/Textures/Mobs/Silicon/chassis.rsi/janitor_moving.png new file mode 100644 index 0000000000000000000000000000000000000000..ff7d4eb483ab447cc836098870e3e609af530e1b GIT binary patch literal 4280 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 Ca&4>t literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Silicon/chassis.rsi/medical.png b/Resources/Textures/Mobs/Silicon/chassis.rsi/medical.png index 4be26cce2f447e6aeced62eb58c3edba4422f7f4..86f26f52cf2c3795fdf03eb78ad343e1a31060b4 100644 GIT binary patch delta 3172 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 KMNUMnLSTX@gFsdQ delta 3317 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 diff --git a/Resources/Textures/Mobs/Silicon/chassis.rsi/medical_moving.png b/Resources/Textures/Mobs/Silicon/chassis.rsi/medical_moving.png new file mode 100644 index 0000000000000000000000000000000000000000..4be26cce2f447e6aeced62eb58c3edba4422f7f4 GIT binary patch literal 3342 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 literal 2958 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