diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 57e2e3d2aa..627238f6e3 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -107,7 +107,6 @@ namespace Content.Client "WeaponCapacitorCharger", "PowerCellCharger", "AiController", - "PlayerInputMover", "Computer", "AsteroidRock", "ResearchServer", @@ -120,13 +119,10 @@ namespace Content.Client "Airlock", "MedicalScanner", "WirePlacer", - "Species", "Drink", "Food", "FoodContainer", "Stomach", - "Hunger", - "Thirst", "Rotatable", "MagicMirror", "MedkitFill", @@ -142,7 +138,6 @@ namespace Content.Client "Bloodstream", "TransformableContainer", "Mind", - "MovementSpeedModifier", "StorageFill", "Mop", "Bucket", @@ -161,7 +156,6 @@ namespace Content.Client "DroppedBodyPart", "DroppedMechanism", "BodyManager", - "Stunnable", "SolarPanel", "BodyScanner", "Stunbaton", diff --git a/Content.Client/GameObjects/Components/Mobs/SpeciesComponent.cs b/Content.Client/GameObjects/Components/Mobs/SpeciesComponent.cs new file mode 100644 index 0000000000..92d3c9b422 --- /dev/null +++ b/Content.Client/GameObjects/Components/Mobs/SpeciesComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Shared.GameObjects; + +namespace Content.Client.GameObjects.Components.Mobs +{ + [RegisterComponent] + [ComponentReference(typeof(SharedSpeciesComponent))] + public class SpeciesComponent : SharedSpeciesComponent + { + + } +} diff --git a/Content.Client/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Client/GameObjects/Components/Mobs/StunnableComponent.cs new file mode 100644 index 0000000000..7ff78391ca --- /dev/null +++ b/Content.Client/GameObjects/Components/Mobs/StunnableComponent.cs @@ -0,0 +1,43 @@ +using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.Components.Movement; +using Robust.Shared.GameObjects; + +#nullable enable + +namespace Content.Client.GameObjects.Components.Mobs +{ + [RegisterComponent] + [ComponentReference(typeof(SharedStunnableComponent))] + public class StunnableComponent : SharedStunnableComponent + { + private bool _stunned; + private bool _knockedDown; + private bool _slowedDown; + + public override bool Stunned => _stunned; + public override bool KnockedDown => _knockedDown; + public override bool SlowedDown => _slowedDown; + + public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) + { + base.HandleComponentState(curState, nextState); + + if (!(curState is StunnableComponentState state)) + { + return; + } + + _stunned = state.Stunned; + _knockedDown = state.KnockedDown; + _slowedDown = state.SlowedDown; + + WalkModifierOverride = state.WalkModifierOverride; + RunModifierOverride = state.RunModifierOverride; + + if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) + { + movement.RefreshMovementSpeedModifiers(); + } + } + } +} diff --git a/Content.Client/GameObjects/Components/Movement/PlayerInputMoverComponent.cs b/Content.Client/GameObjects/Components/Movement/PlayerInputMoverComponent.cs new file mode 100644 index 0000000000..50bcbd2790 --- /dev/null +++ b/Content.Client/GameObjects/Components/Movement/PlayerInputMoverComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared.GameObjects.Components.Movement; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; + +#nullable enable + +namespace Content.Client.GameObjects.Components.Movement +{ + [RegisterComponent] + [ComponentReference(typeof(IMoverComponent))] + public class PlayerInputMoverComponent : SharedPlayerInputMoverComponent, IMoverComponent + { + public override GridCoordinates LastPosition { get; set; } + public override float StepSoundDistance { get; set; } + } +} diff --git a/Content.Client/GameObjects/Components/Nutrition/HungerComponent.cs b/Content.Client/GameObjects/Components/Nutrition/HungerComponent.cs new file mode 100644 index 0000000000..fa66e98812 --- /dev/null +++ b/Content.Client/GameObjects/Components/Nutrition/HungerComponent.cs @@ -0,0 +1,30 @@ +using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Nutrition; +using Robust.Shared.GameObjects; + +#nullable enable + +namespace Content.Client.GameObjects.Components.Nutrition +{ + [RegisterComponent] + public class HungerComponent : SharedHungerComponent + { + private HungerThreshold _currentHungerThreshold; + public override HungerThreshold CurrentHungerThreshold => _currentHungerThreshold; + + public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) + { + if (!(curState is HungerComponentState hunger)) + { + return; + } + + _currentHungerThreshold = hunger.CurrentThreshold; + + if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) + { + movement.RefreshMovementSpeedModifiers(); + } + } + } +} diff --git a/Content.Client/GameObjects/Components/Nutrition/ThirstComponent.cs b/Content.Client/GameObjects/Components/Nutrition/ThirstComponent.cs new file mode 100644 index 0000000000..10b63d054b --- /dev/null +++ b/Content.Client/GameObjects/Components/Nutrition/ThirstComponent.cs @@ -0,0 +1,30 @@ +using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Nutrition; +using Robust.Shared.GameObjects; + +#nullable enable + +namespace Content.Client.GameObjects.Components.Nutrition +{ + [RegisterComponent] + public class ThirstComponent : SharedThirstComponent + { + private ThirstThreshold _currentThirstThreshold; + public override ThirstThreshold CurrentThirstThreshold => _currentThirstThreshold; + + public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) + { + if (!(curState is ThirstComponentState thirst)) + { + return; + } + + _currentThirstThreshold = thirst.CurrentThreshold; + + if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) + { + movement.RefreshMovementSpeedModifiers(); + } + } + } +} diff --git a/Content.Client/GameObjects/EntitySystems/MoverSystem.cs b/Content.Client/GameObjects/EntitySystems/MoverSystem.cs new file mode 100644 index 0000000000..daceb2e44f --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/MoverSystem.cs @@ -0,0 +1,54 @@ +using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.Physics; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.Physics; +using Robust.Client.Player; +using Robust.Shared.GameObjects.Components; +using Robust.Shared.IoC; +using Robust.Shared.Physics; + +#nullable enable + +namespace Content.Client.GameObjects.EntitySystems +{ + [UsedImplicitly] + public class MoverSystem : SharedMoverSystem + { + [Dependency] private readonly IPlayerManager _playerManager = default!; + + public override void Initialize() + { + base.Initialize(); + + UpdatesBefore.Add(typeof(PhysicsSystem)); + } + + public override void FrameUpdate(float frameTime) + { + var playerEnt = _playerManager.LocalPlayer?.ControlledEntity; + + if (playerEnt == null || !playerEnt.TryGetComponent(out IMoverComponent mover)) + { + return; + } + + var physics = playerEnt.GetComponent(); + playerEnt.TryGetComponent(out CollidableComponent? collidable); + physics.Predict = true; + + UpdateKinematics(playerEnt.Transform, mover, physics, collidable); + } + + public override void Update(float frameTime) + { + FrameUpdate(frameTime); + } + + protected override void SetController(SharedPhysicsComponent physics) + { + ((PhysicsComponent)physics).SetController(); + } + } +} diff --git a/Content.Client/GameObjects/EntitySystems/VerbSystem.cs b/Content.Client/GameObjects/EntitySystems/VerbSystem.cs index 28bed30120..33710ce83b 100644 --- a/Content.Client/GameObjects/EntitySystems/VerbSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/VerbSystem.cs @@ -444,7 +444,7 @@ namespace Content.Client.GameObjects.EntitySystems var func = args.Function; var funcId = _master._inputManager.NetworkBindMap.KeyFunctionID(args.Function); - var message = new FullInputCmdMessage(_master._gameTiming.CurTick, funcId, BoundKeyState.Down, + var message = new FullInputCmdMessage(_master._gameTiming.CurTick, _master._gameTiming.TickFraction, funcId, BoundKeyState.Down, _entity.Transform.GridPosition, args.PointerLocation, _entity.Uid); diff --git a/Content.Client/State/GameScreenBase.cs b/Content.Client/State/GameScreenBase.cs index f407af9fe1..b11201eca3 100644 --- a/Content.Client/State/GameScreenBase.cs +++ b/Content.Client/State/GameScreenBase.cs @@ -195,7 +195,7 @@ namespace Content.Client.State if (!_mapManager.TryFindGridAt(mousePosWorld, out var grid)) grid = _mapManager.GetDefaultGrid(mousePosWorld.MapId); - var message = new FullInputCmdMessage(_timing.CurTick, funcId, args.State, + var message = new FullInputCmdMessage(_timing.CurTick, _timing.TickFraction, funcId, args.State, grid.MapToGrid(mousePosWorld), args.PointerLocation, entityToClick?.Uid ?? EntityUid.Invalid); diff --git a/Content.Client/UserInterface/ItemSlotManager.cs b/Content.Client/UserInterface/ItemSlotManager.cs index c5eb215fab..5ddbc93fbc 100644 --- a/Content.Client/UserInterface/ItemSlotManager.cs +++ b/Content.Client/UserInterface/ItemSlotManager.cs @@ -77,7 +77,7 @@ namespace Content.Client.UserInterface if (!_mapManager.TryFindGridAt(mousePosWorld, out var grid)) grid = _mapManager.GetDefaultGrid(mousePosWorld.MapId); - var message = new FullInputCmdMessage(_gameTiming.CurTick, funcId, BoundKeyState.Down, + var message = new FullInputCmdMessage(_gameTiming.CurTick, _gameTiming.TickFraction, funcId, BoundKeyState.Down, grid.MapToGrid(mousePosWorld), args.PointerLocation, item.Uid); // client side command handlers will always be sent the local player session. diff --git a/Content.Server/AI/Operators/Movement/BaseMover.cs b/Content.Server/AI/Operators/Movement/BaseMover.cs index cbbd5acdae..a491de14fb 100644 --- a/Content.Server/AI/Operators/Movement/BaseMover.cs +++ b/Content.Server/AI/Operators/Movement/BaseMover.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Threading; using Content.Server.GameObjects.Components.Access; using Content.Server.GameObjects.Components.Movement; -using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems.AI.Pathfinding; using Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders; using Content.Server.GameObjects.EntitySystems.JobQueues; +using Content.Shared.GameObjects.EntitySystems; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; diff --git a/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs b/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs index 5702009b0a..5d9949508e 100644 --- a/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs +++ b/Content.Server/AI/Utility/Considerations/ActionBlocker/CanMoveCon.cs @@ -1,7 +1,7 @@ using Content.Server.AI.Utility.Curves; using Content.Server.AI.WorldState; using Content.Server.AI.WorldState.States; -using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.EntitySystems; namespace Content.Server.AI.Utility.Considerations.ActionBlocker { diff --git a/Content.Server/AI/Utility/Considerations/Nutrition/Drink/ThirstCon.cs b/Content.Server/AI/Utility/Considerations/Nutrition/Drink/ThirstCon.cs index 02e8719d2a..e2c387fbbc 100644 --- a/Content.Server/AI/Utility/Considerations/Nutrition/Drink/ThirstCon.cs +++ b/Content.Server/AI/Utility/Considerations/Nutrition/Drink/ThirstCon.cs @@ -2,6 +2,7 @@ using Content.Server.AI.Utility.Curves; using Content.Server.AI.WorldState; using Content.Server.AI.WorldState.States; using Content.Server.GameObjects.Components.Nutrition; +using Content.Shared.GameObjects.Components.Nutrition; namespace Content.Server.AI.Utility.Considerations.Nutrition.Drink { diff --git a/Content.Server/AI/Utility/Considerations/Nutrition/Food/HungerCon.cs b/Content.Server/AI/Utility/Considerations/Nutrition/Food/HungerCon.cs index 170e7d22b8..2d154e12f5 100644 --- a/Content.Server/AI/Utility/Considerations/Nutrition/Food/HungerCon.cs +++ b/Content.Server/AI/Utility/Considerations/Nutrition/Food/HungerCon.cs @@ -2,6 +2,7 @@ using Content.Server.AI.Utility.Curves; using Content.Server.AI.WorldState; using Content.Server.AI.WorldState.States; using Content.Server.GameObjects.Components.Nutrition; +using Content.Shared.GameObjects.Components.Nutrition; namespace Content.Server.AI.Utility.Considerations.Nutrition { diff --git a/Content.Server/AI/WorldState/States/Nutrition/HungryState.cs b/Content.Server/AI/WorldState/States/Nutrition/HungryState.cs index 2143a827b3..b936e47f3d 100644 --- a/Content.Server/AI/WorldState/States/Nutrition/HungryState.cs +++ b/Content.Server/AI/WorldState/States/Nutrition/HungryState.cs @@ -1,5 +1,6 @@ using System; using Content.Server.GameObjects.Components.Nutrition; +using Content.Shared.GameObjects.Components.Nutrition; using JetBrains.Annotations; namespace Content.Server.AI.WorldState.States.Nutrition diff --git a/Content.Server/AI/WorldState/States/Nutrition/ThirstyState.cs b/Content.Server/AI/WorldState/States/Nutrition/ThirstyState.cs index 02ea016c56..65877facf2 100644 --- a/Content.Server/AI/WorldState/States/Nutrition/ThirstyState.cs +++ b/Content.Server/AI/WorldState/States/Nutrition/ThirstyState.cs @@ -1,5 +1,6 @@ using System; using Content.Server.GameObjects.Components.Nutrition; +using Content.Shared.GameObjects.Components.Nutrition; using JetBrains.Annotations; using ThirstComponent = Content.Server.GameObjects.Components.Nutrition.ThirstComponent; diff --git a/Content.Server/Chat/ChatManager.cs b/Content.Server/Chat/ChatManager.cs index f4f3df49e0..f36474ba1e 100644 --- a/Content.Server/Chat/ChatManager.cs +++ b/Content.Server/Chat/ChatManager.cs @@ -6,6 +6,7 @@ using Content.Server.Interfaces.Chat; using Content.Server.Observer; using Content.Server.Players; using Content.Shared.Chat; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.Interfaces.Player; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; diff --git a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs index 63261077ae..e9ff6f744f 100644 --- a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs @@ -8,6 +8,7 @@ using Content.Server.Interfaces.GameObjects; using Content.Server.Utility; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Chemistry; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs index 8d023d2580..96b2dec4d7 100644 --- a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs @@ -17,6 +17,7 @@ using Robust.Shared.Utility; using Robust.Shared.ViewVariables; using System.Collections.Generic; using System.Linq; +using Content.Shared.GameObjects.EntitySystems; using Robust.Shared.GameObjects.Systems; namespace Content.Server.GameObjects.Components.Chemistry diff --git a/Content.Server/GameObjects/Components/Fluids/CanSpillComponent.cs b/Content.Server/GameObjects/Components/Fluids/CanSpillComponent.cs index 2c4cfc80f3..e52172a4cd 100644 --- a/Content.Server/GameObjects/Components/Fluids/CanSpillComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/CanSpillComponent.cs @@ -3,6 +3,7 @@ using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Chemistry; using Content.Shared.GameObjects; +using Content.Shared.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs index 40db217526..6f5fc254fa 100644 --- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks.Dataflow; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Shared.GameObjects; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects.Components.Container; using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs index 4f9b1158fc..ca6e19e3b8 100644 --- a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs +++ b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs @@ -3,11 +3,9 @@ using System.Linq; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; -using Content.Server.Interfaces.GameObjects; using Content.Server.Mobs; -using Content.Server.Utility; using Content.Shared.GameObjects.Components.Instruments; -using NFluidsynth; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.Interfaces.GameObjects; @@ -15,16 +13,12 @@ using Robust.Server.Interfaces.Player; using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Log; using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Players; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; -using Logger = Robust.Shared.Log.Logger; -using MidiEvent = Robust.Shared.Audio.Midi.MidiEvent; namespace Content.Server.GameObjects.Components.Instruments { diff --git a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs index 2e58ab6b6c..8df9819af5 100644 --- a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs @@ -5,6 +5,7 @@ using Content.Server.Interfaces.GameObjects; using Content.Server.Utility; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; diff --git a/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs b/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs index 54e64c90e1..9d1469489e 100644 --- a/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs @@ -12,6 +12,7 @@ using Content.Shared.Chemistry; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components.Interactable; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Maps; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs index e3a7bab178..9b4eb1f58b 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs @@ -7,6 +7,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.Components.Storage; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; diff --git a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs index 0e34998d11..e352f9b42e 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs @@ -7,6 +7,7 @@ using Content.Server.Throw; using Content.Server.Utility; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Items; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Physics; using Robust.Server.GameObjects; using Robust.Server.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs index d37f3b79c7..9f583e5a09 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs @@ -3,6 +3,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Storage; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs index f309e1bce5..08d7c86f77 100644 --- a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs +++ b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs @@ -5,6 +5,7 @@ using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Medical; using Content.Server.GameObjects.Components.Power; using Content.Server.Utility; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.Components.UserInterface; diff --git a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs index ed558fc981..abfdcb52f0 100644 --- a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs +++ b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs @@ -3,6 +3,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Server.Mobs; using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.EntitySystems; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; diff --git a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs index bae8e11772..380f93d667 100644 --- a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs @@ -3,21 +3,22 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; -using Content.Server.Interfaces.GameObjects.Components.Movement; using Content.Server.Observer; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects; using Robust.Server.Interfaces.Player; -using Robust.Shared.ContentPack; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Network; +using Robust.Shared.Players; using Robust.Shared.Serialization; namespace Content.Server.GameObjects { [RegisterComponent] + [ComponentReference(typeof(SharedSpeciesComponent))] public class SpeciesComponent : SharedSpeciesComponent, IActionBlocker, IOnDamageBehavior, IExAct, IRelayMoveInput { /// @@ -218,11 +219,11 @@ namespace Content.Server.GameObjects Owner.GetComponent().TakeDamage(DamageType.Heat, burnDamage, null); } - void IRelayMoveInput.MoveInputPressed(IPlayerSession session) + void IRelayMoveInput.MoveInputPressed(ICommonSession session) { if (CurrentDamageState is DeadState) { - new Ghost().Execute(null, session, null); + new Ghost().Execute(null, (IPlayerSession) session, null); } } } diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index fbbd165230..e9930546ef 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -1,50 +1,40 @@ using System; using System.Threading; -using Content.Server.GameObjects.Components.Movement; using Content.Server.GameObjects.EntitySystems; -using Content.Server.Interfaces.GameObjects; using Content.Server.Mobs; using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Mobs; -using Microsoft.Extensions.Logging; -using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; -using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Timers; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; -using Robust.Shared.Log; -using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; using Timer = Robust.Shared.Timers.Timer; -using CannyFastMath; +using Content.Shared.GameObjects.Components.Movement; using Math = CannyFastMath.Math; using MathF = CannyFastMath.MathF; namespace Content.Server.GameObjects.Components.Mobs { [RegisterComponent] - public class StunnableComponent : Component, IActionBlocker, IInteractHand, IMoveSpeedModifier + [ComponentReference(typeof(SharedStunnableComponent))] + public class StunnableComponent : SharedStunnableComponent, IInteractHand { - public override string Name => "Stunnable"; - #pragma warning disable 649 [Dependency] private IGameTiming _gameTiming; #pragma warning restore 649 private TimeSpan? _lastStun; - [ViewVariables] - public TimeSpan? StunStart => _lastStun; + [ViewVariables] public TimeSpan? StunStart => _lastStun; [ViewVariables] public TimeSpan? StunEnd => _lastStun == null ? (TimeSpan?) null - : _gameTiming.CurTime + (TimeSpan.FromSeconds(Math.Max(_stunnedTimer, Math.Max(_knockdownTimer, _slowdownTimer)))); + : _gameTiming.CurTime + + (TimeSpan.FromSeconds(Math.Max(_stunnedTimer, Math.Max(_knockdownTimer, _slowdownTimer)))); private const int StunLevels = 8; @@ -59,14 +49,12 @@ namespace Content.Server.GameObjects.Components.Mobs private float _knockdownTimer = 0f; private float _slowdownTimer = 0f; - private float _walkModifierOverride = 0f; - private float _runModifierOverride = 0f; private string _stunTexture; private CancellationTokenSource _statusRemoveCancellation = new CancellationTokenSource(); - [ViewVariables] public bool Stunned => _stunnedTimer > 0f; - [ViewVariables] public bool KnockedDown => _knockdownTimer > 0f; - [ViewVariables] public bool SlowedDown => _slowdownTimer > 0f; + [ViewVariables] public override bool Stunned => _stunnedTimer > 0f; + [ViewVariables] public override bool KnockedDown => _knockdownTimer > 0f; + [ViewVariables] public override bool SlowedDown => _slowdownTimer > 0f; [ViewVariables] public float StunCap => _stunCap; [ViewVariables] public float KnockdownCap => _knockdownCap; [ViewVariables] public float SlowdownCap => _slowdownCap; @@ -79,7 +67,8 @@ namespace Content.Server.GameObjects.Components.Mobs serializer.DataField(ref _slowdownCap, "slowdownCap", 20f); serializer.DataField(ref _helpInterval, "helpInterval", 1f); serializer.DataField(ref _helpKnockdownRemove, "helpKnockdownRemove", 1f); - serializer.DataField(ref _stunTexture, "stunTexture", "/Textures/Objects/Melee/stunbaton.rsi/stunbaton_off.png"); + serializer.DataField(ref _stunTexture, "stunTexture", + "/Textures/Objects/Melee/stunbaton.rsi/stunbaton_off.png"); } /// @@ -99,6 +88,7 @@ namespace Content.Server.GameObjects.Components.Mobs _lastStun = _gameTiming.CurTime; SetStatusEffect(); + Dirty(); } /// @@ -118,6 +108,7 @@ namespace Content.Server.GameObjects.Components.Mobs _lastStun = _gameTiming.CurTime; SetStatusEffect(); + Dirty(); } /// @@ -143,16 +134,17 @@ namespace Content.Server.GameObjects.Components.Mobs if (seconds <= 0f) return; - _walkModifierOverride = walkModifierOverride; - _runModifierOverride = runModifierOverride; + WalkModifierOverride = walkModifierOverride; + RunModifierOverride = runModifierOverride; _slowdownTimer = seconds; _lastStun = _gameTiming.CurTime; - if(Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) + if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) movement.RefreshMovementSpeedModifiers(); SetStatusEffect(); + Dirty(); } /// @@ -162,6 +154,7 @@ namespace Content.Server.GameObjects.Components.Mobs { _knockdownTimer = 0f; _stunnedTimer = 0f; + Dirty(); } public bool InteractHand(InteractHandEventArgs eventArgs) @@ -170,7 +163,7 @@ namespace Content.Server.GameObjects.Components.Mobs return false; _canHelp = false; - Timer.Spawn(((int)_helpInterval*1000), () => _canHelp = true); + Timer.Spawn(((int) _helpInterval * 1000), () => _canHelp = true); EntitySystem.Get() .PlayFromEntity("/Audio/effects/thudswoosh.ogg", Owner, AudioHelpers.WithVariation(0.25f)); @@ -179,6 +172,7 @@ namespace Content.Server.GameObjects.Components.Mobs SetStatusEffect(); + Dirty(); return true; } @@ -187,7 +181,8 @@ namespace Content.Server.GameObjects.Components.Mobs if (!Owner.TryGetComponent(out ServerStatusEffectsComponent status)) return; - status.ChangeStatusEffect(StatusEffect.Stun, _stunTexture, (StunStart == null || StunEnd == null) ? default : (StunStart.Value, StunEnd.Value)); + status.ChangeStatusEffect(StatusEffect.Stun, _stunTexture, + (StunStart == null || StunEnd == null) ? default : (StunStart.Value, StunEnd.Value)); _statusRemoveCancellation.Cancel(); _statusRemoveCancellation = new CancellationTokenSource(); } @@ -212,6 +207,7 @@ namespace Content.Server.GameObjects.Components.Mobs if (_stunnedTimer <= 0) { _stunnedTimer = 0f; + Dirty(); } } @@ -224,6 +220,7 @@ namespace Content.Server.GameObjects.Components.Mobs StandingStateHelper.Standing(Owner); _knockdownTimer = 0f; + Dirty(); } } @@ -235,12 +232,14 @@ namespace Content.Server.GameObjects.Components.Mobs { _slowdownTimer = 0f; - if(Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) + if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) movement.RefreshMovementSpeedModifiers(); + Dirty(); } } - if (!StunStart.HasValue || !StunEnd.HasValue || !Owner.TryGetComponent(out ServerStatusEffectsComponent status)) + if (!StunStart.HasValue || !StunEnd.HasValue || + !Owner.TryGetComponent(out ServerStatusEffectsComponent status)) return; var start = StunStart.Value; @@ -256,31 +255,6 @@ namespace Content.Server.GameObjects.Components.Mobs } } - #region ActionBlockers - public bool CanMove() => (!Stunned); - - public bool CanInteract() => (!Stunned); - - public bool CanUse() => (!Stunned); - - public bool CanThrow() => (!Stunned); - - public bool CanSpeak() => true; - - public bool CanDrop() => (!Stunned); - - public bool CanPickup() => (!Stunned); - - public bool CanEmote() => true; - - public bool CanAttack() => (!Stunned); - - public bool CanEquip() => (!Stunned); - - public bool CanUnequip() => (!Stunned); - public bool CanChangeDirection() => true; - #endregion - public float StunTimeModifier { get @@ -329,8 +303,11 @@ namespace Content.Server.GameObjects.Components.Mobs } } - public float WalkSpeedModifier => (SlowedDown ? (_walkModifierOverride <= 0f ? 0.5f : _walkModifierOverride) : 1f); - public float SprintSpeedModifier => (SlowedDown ? (_runModifierOverride <= 0f ? 0.5f : _runModifierOverride) : 1f); + public override ComponentState GetComponentState() + { + return new StunnableComponentState(Stunned, KnockedDown, SlowedDown, WalkModifierOverride, + RunModifierOverride); + } } /// diff --git a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs index 6a6747c6bb..61739f4029 100644 --- a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs @@ -1,6 +1,4 @@ -using Content.Server.AI.Utility; -using Content.Server.AI.Utility.AiLogic; -using Content.Server.Interfaces.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Movement; using Robust.Server.AI; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; @@ -111,7 +109,7 @@ namespace Content.Server.GameObjects.Components.Movement /// Is the entity Sprinting (running)? /// [ViewVariables] - public bool Sprinting { get; set; } = true; + public bool Sprinting { get; } = true; /// /// Calculated linear velocity direction of the entity. @@ -119,11 +117,14 @@ namespace Content.Server.GameObjects.Components.Movement [ViewVariables] public Vector2 VelocityDir { get; set; } + (Vector2 walking, Vector2 sprinting) IMoverComponent.VelocityDir => + Sprinting ? (Vector2.Zero, VelocityDir) : (VelocityDir, Vector2.Zero); + public GridCoordinates LastPosition { get; set; } - [ViewVariables(VVAccess.ReadWrite)] - public float StepSoundDistance { get; set; } + [ViewVariables(VVAccess.ReadWrite)] public float StepSoundDistance { get; set; } - public void SetVelocityDirection(Direction direction, bool enabled) { } + public void SetVelocityDirection(Direction direction, ushort subTick, bool enabled) { } + public void SetSprinting(ushort subTick, bool walking) { } } } diff --git a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs index f15f81f8fd..e1e617774e 100644 --- a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs @@ -1,17 +1,11 @@ - -using Content.Server.Interfaces.GameObjects.Components.Movement; -using Robust.Server.GameObjects; +using Content.Shared.GameObjects.Components.Movement; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; -using Robust.Shared.Log; using Robust.Shared.Map; -using Robust.Shared.Maths; using Robust.Shared.Physics; -using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; -using Robust.Shared.IoC; -using Robust.Shared.Interfaces.Configuration; -using Robust.Shared.Configuration; + +#nullable enable namespace Content.Server.GameObjects.Components.Movement { @@ -20,153 +14,10 @@ namespace Content.Server.GameObjects.Components.Movement /// [RegisterComponent] [ComponentReference(typeof(IMoverComponent))] - public class PlayerInputMoverComponent : Component, IMoverComponent, ICollideSpecial + public class PlayerInputMoverComponent : SharedPlayerInputMoverComponent { -#pragma warning disable 649 - [Dependency] private readonly IConfigurationManager _configurationManager; -#pragma warning restore 649 - - private bool _movingUp; - private bool _movingDown; - private bool _movingLeft; - private bool _movingRight; - - /// - public override string Name => "PlayerInputMover"; - - /// - /// Movement speed (m/s) that the entity walks, after modifiers - /// - [ViewVariables] - public float CurrentWalkSpeed - { - get - { - if (Owner.TryGetComponent(out MovementSpeedModifierComponent component)) - { - return component.CurrentWalkSpeed; - } - - return MovementSpeedModifierComponent.DefaultBaseWalkSpeed; - } - } - /// - /// Movement speed (m/s) that the entity walks, after modifiers - /// - [ViewVariables] - public float CurrentSprintSpeed - { - get - { - if (Owner.TryGetComponent(out MovementSpeedModifierComponent component)) - { - return component.CurrentSprintSpeed; - } - - return MovementSpeedModifierComponent.DefaultBaseSprintSpeed; - } - } - - /// - [ViewVariables] - public float CurrentPushSpeed => 5.0f; - - /// - [ViewVariables] - public float GrabRange => 0.2f; - - /// - /// Is the entity Sprinting (running)? - /// - [ViewVariables] - public bool Sprinting { get; set; } = true; - - /// - /// Calculated linear velocity direction of the entity. - /// - [ViewVariables] - public Vector2 VelocityDir { get; private set; } - - public GridCoordinates LastPosition { get; set; } - - public float StepSoundDistance { get; set; } - - /// - /// Whether or not the player can move diagonally. - /// - [ViewVariables] public bool DiagonalMovementEnabled => _configurationManager.GetCVar("game.diagonalmovement"); - - /// - public override void OnAdd() - { - // This component requires that the entity has a PhysicsComponent. - if (!Owner.HasComponent()) - Logger.Error($"[ECS] {Owner.Prototype.Name} - {nameof(PlayerInputMoverComponent)} requires {nameof(PhysicsComponent)}. "); - - base.OnAdd(); - } - - /// - /// Toggles one of the four cardinal directions. Each of the four directions are - /// composed into a single direction vector, . Enabling - /// opposite directions will cancel each other out, resulting in no direction. - /// - /// Direction to toggle. - /// If the direction is active. - public void SetVelocityDirection(Direction direction, bool enabled) - { - switch (direction) - { - case Direction.East: - _movingRight = enabled; - break; - case Direction.North: - _movingUp = enabled; - break; - case Direction.West: - _movingLeft = enabled; - break; - case Direction.South: - _movingDown = enabled; - break; - } - - // key directions are in screen coordinates - // _moveDir is in world coordinates - // if the camera is moved, this needs to be changed - - var x = 0; - x -= _movingLeft ? 1 : 0; - x += _movingRight ? 1 : 0; - - var y = 0; - if (DiagonalMovementEnabled || x == 0) - { - y -= _movingDown ? 1 : 0; - y += _movingUp ? 1 : 0; - } - - VelocityDir = new Vector2(x, y); - - // can't normalize zero length vector - if (VelocityDir.LengthSquared > 1.0e-6) - VelocityDir = VelocityDir.Normalized; - } - - /// - /// Special collision override, can be used to give custom behaviors deciding when to collide - /// - /// - /// - bool ICollideSpecial.PreventCollide(IPhysBody collidedwith) - { - // Don't collide with other mobs - if (collidedwith.Owner.TryGetComponent(out var collidedSpeciesComponent)) - { - return true; - } - return false; - } + public override GridCoordinates LastPosition { get; set; } + public override float StepSoundDistance { get; set; } } } diff --git a/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs b/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs index e78695c0a0..d541b4d686 100644 --- a/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs @@ -1,5 +1,5 @@ using Content.Server.GameObjects.Components.Mobs; -using Content.Server.Interfaces.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Movement; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Shared.GameObjects; @@ -44,11 +44,11 @@ namespace Content.Server.GameObjects.Components.Movement public float GrabRange => 0.0f; public bool Sprinting { get; set; } - public Vector2 VelocityDir { get; } = Vector2.Zero; + public (Vector2 walking, Vector2 sprinting) VelocityDir { get; } = (Vector2.Zero, Vector2.Zero); public GridCoordinates LastPosition { get; set; } public float StepSoundDistance { get; set; } - public void SetVelocityDirection(Direction direction, bool enabled) + public void SetVelocityDirection(Direction direction, ushort subTick, bool enabled) { var gridId = Owner.Transform.GridID; @@ -74,6 +74,11 @@ namespace Content.Server.GameObjects.Components.Movement } } + public void SetSprinting(ushort subTick, bool walking) + { + // Shuttles can't sprint. + } + private Vector2 CalcNewVelocity(Direction direction, bool enabled) { switch (direction) diff --git a/Content.Server/GameObjects/Components/Nutrition/HungerComponent.cs b/Content.Server/GameObjects/Components/Nutrition/HungerComponent.cs index cd557b1ad4..82233841b4 100644 --- a/Content.Server/GameObjects/Components/Nutrition/HungerComponent.cs +++ b/Content.Server/GameObjects/Components/Nutrition/HungerComponent.cs @@ -4,6 +4,8 @@ using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Movement; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Nutrition; using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.Random; @@ -15,14 +17,12 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Nutrition { [RegisterComponent] - public sealed class HungerComponent : Component, IMoveSpeedModifier + public sealed class HungerComponent : SharedHungerComponent { #pragma warning disable 649 [Dependency] private readonly IRobustRandom _random; #pragma warning restore 649 - public override string Name => "Hunger"; - // Base stuff public float BaseDecayRate => _baseDecayRate; [ViewVariables] private float _baseDecayRate; @@ -30,7 +30,7 @@ namespace Content.Server.GameObjects.Components.Nutrition [ViewVariables] private float _actualDecayRate; // Hunger - public HungerThreshold CurrentHungerThreshold => _currentHungerThreshold; + public override HungerThreshold CurrentHungerThreshold => _currentHungerThreshold; private HungerThreshold _currentHungerThreshold; private HungerThreshold _lastHungerThreshold; public float CurrentHunger => _currentHunger; @@ -127,6 +127,7 @@ namespace Content.Server.GameObjects.Components.Nutrition _currentHungerThreshold = GetHungerThreshold(_currentHunger); _lastHungerThreshold = HungerThreshold.Okay; // TODO: Potentially change this -> Used Okay because no effects. HungerThresholdEffect(true); + Dirty(); } public HungerThreshold GetHungerThreshold(float food) @@ -161,6 +162,7 @@ namespace Content.Server.GameObjects.Components.Nutrition { _currentHungerThreshold = calculatedHungerThreshold; HungerThresholdEffect(); + Dirty(); } if (_currentHungerThreshold == HungerThreshold.Dead) { @@ -179,36 +181,11 @@ namespace Content.Server.GameObjects.Components.Nutrition _currentHunger = HungerThresholds[HungerThreshold.Okay]; } - float IMoveSpeedModifier.WalkSpeedModifier + public override ComponentState GetComponentState() { - get - { - if (_currentHungerThreshold == HungerThreshold.Starving) - { - return 0.5f; - } - return 1.0f; - } - } - float IMoveSpeedModifier.SprintSpeedModifier - { - get - { - if (_currentHungerThreshold == HungerThreshold.Starving) - { - return 0.5f; - } - return 1.0f; - } + return new HungerComponentState(_currentHungerThreshold); } } - public enum HungerThreshold - { - Overfed, - Okay, - Peckish, - Starving, - Dead, - } + } diff --git a/Content.Server/GameObjects/Components/Nutrition/ThirstComponent.cs b/Content.Server/GameObjects/Components/Nutrition/ThirstComponent.cs index 2d64123ef3..cfd820e5e2 100644 --- a/Content.Server/GameObjects/Components/Nutrition/ThirstComponent.cs +++ b/Content.Server/GameObjects/Components/Nutrition/ThirstComponent.cs @@ -4,6 +4,8 @@ using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Movement; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Nutrition; using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.Random; @@ -15,14 +17,12 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Nutrition { [RegisterComponent] - public sealed class ThirstComponent : Component, IMoveSpeedModifier + public sealed class ThirstComponent : SharedThirstComponent, IMoveSpeedModifier { #pragma warning disable 649 [Dependency] private readonly IRobustRandom _random; #pragma warning restore 649 - public override string Name => "Thirst"; - // Base stuff public float BaseDecayRate => _baseDecayRate; [ViewVariables] private float _baseDecayRate; @@ -30,7 +30,7 @@ namespace Content.Server.GameObjects.Components.Nutrition [ViewVariables] private float _actualDecayRate; // Thirst - public ThirstThreshold CurrentThirstThreshold => _currentThirstThreshold; + public override ThirstThreshold CurrentThirstThreshold => _currentThirstThreshold; private ThirstThreshold _currentThirstThreshold; private ThirstThreshold _lastThirstThreshold; public float CurrentThirst => _currentThirst; @@ -126,6 +126,7 @@ namespace Content.Server.GameObjects.Components.Nutrition _lastThirstThreshold = ThirstThreshold.Okay; // TODO: Potentially change this -> Used Okay because no effects. // TODO: Check all thresholds make sense and throw if they don't. ThirstThresholdEffect(true); + Dirty(); } public ThirstThreshold GetThirstThreshold(float drink) @@ -160,6 +161,7 @@ namespace Content.Server.GameObjects.Components.Nutrition { _currentThirstThreshold = calculatedThirstThreshold; ThirstThresholdEffect(); + Dirty(); } if (_currentThirstThreshold == ThirstThreshold.Dead) @@ -174,42 +176,16 @@ namespace Content.Server.GameObjects.Components.Nutrition } } - float IMoveSpeedModifier.SprintSpeedModifier - { - get - { - if (_currentThirstThreshold == ThirstThreshold.Parched) - { - return 0.25f; - } - return 1.0f; - } - } - float IMoveSpeedModifier.WalkSpeedModifier - { - get - { - if (_currentThirstThreshold == ThirstThreshold.Parched) - { - return 0.5f; - } - return 1.0f; - } - } public void ResetThirst() { _currentThirst = ThirstThresholds[ThirstThreshold.Okay]; } + + public override ComponentState GetComponentState() + { + return new ThirstComponentState(_currentThirstThreshold); + } } - public enum ThirstThreshold - { - // Hydrohomies - OverHydrated, - Okay, - Thirsty, - Parched, - Dead, - } } diff --git a/Content.Server/GameObjects/Components/Observer/GhostComponent.cs b/Content.Server/GameObjects/Components/Observer/GhostComponent.cs index b2d2881fcd..9caca4a53c 100644 --- a/Content.Server/GameObjects/Components/Observer/GhostComponent.cs +++ b/Content.Server/GameObjects/Components/Observer/GhostComponent.cs @@ -1,6 +1,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Server.Players; using Content.Shared.GameObjects.Components.Observer; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components; using Robust.Server.Interfaces.GameObjects; @@ -15,7 +16,7 @@ using Timer = Robust.Shared.Timers.Timer; namespace Content.Server.GameObjects.Components.Observer { [RegisterComponent] - public class GhostComponent : SharedGhostComponent, IActionBlocker + public class GhostComponent : SharedGhostComponent { private bool _canReturnToBody = true; @@ -75,13 +76,5 @@ namespace Content.Server.GameObjects.Components.Observer break; } } - - public bool CanInteract() => false; - public bool CanUse() => false; - public bool CanThrow() => false; - public bool CanDrop() => false; - public bool CanPickup() => false; - public bool CanEmote() => false; - public bool CanAttack() => false; } } diff --git a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs index a6dd1deb05..78328c9c94 100644 --- a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs +++ b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs @@ -8,6 +8,7 @@ using Content.Server.Interfaces; using Content.Server.Interfaces.PDA; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.PDA; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.Components.UserInterface; diff --git a/Content.Server/GameObjects/Components/Power/Chargers/PowerCellChargerComponent.cs b/Content.Server/GameObjects/Components/Power/Chargers/PowerCellChargerComponent.cs index f904673e37..0cd13e4ecc 100644 --- a/Content.Server/GameObjects/Components/Power/Chargers/PowerCellChargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/Chargers/PowerCellChargerComponent.cs @@ -3,6 +3,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Server.Utility; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Power; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; diff --git a/Content.Server/GameObjects/Components/Power/Chargers/WeaponCapacitorChargerComponent.cs b/Content.Server/GameObjects/Components/Power/Chargers/WeaponCapacitorChargerComponent.cs index 2bb1bee4d5..a376d37300 100644 --- a/Content.Server/GameObjects/Components/Power/Chargers/WeaponCapacitorChargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/Chargers/WeaponCapacitorChargerComponent.cs @@ -3,6 +3,7 @@ using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Power; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs b/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs index e814a7b0d7..d6daefeb90 100644 --- a/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs +++ b/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs @@ -7,6 +7,7 @@ using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Random; +using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; diff --git a/Content.Server/GameObjects/Components/RotatableComponent.cs b/Content.Server/GameObjects/Components/RotatableComponent.cs index bd45b22e98..8ef6d6484b 100644 --- a/Content.Server/GameObjects/Components/RotatableComponent.cs +++ b/Content.Server/GameObjects/Components/RotatableComponent.cs @@ -1,6 +1,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Shared.GameObjects; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs index 15df71beab..4275e70209 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -5,6 +5,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameObjects; using Content.Shared.Audio; using Content.Shared.GameObjects; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs index 40d48ee25b..9d7d6a869d 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs @@ -5,6 +5,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Shared.Audio; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs index b0e711674b..bdee4823b6 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs @@ -4,6 +4,7 @@ using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs index 1f8ebddb42..1bbd687df2 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs @@ -4,6 +4,7 @@ using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs index 028c0424f8..f10aab172d 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs @@ -5,6 +5,7 @@ using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.Container; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs index 301054ac89..c6cb930c1a 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs @@ -3,6 +3,7 @@ using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Weapons.Ranged; +using Content.Shared.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; @@ -18,11 +19,11 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged public sealed class ServerRangedWeaponComponent : SharedRangedWeaponComponent, IHandSelected { private TimeSpan _lastFireTime; - + public Func WeaponCanFireHandler; public Func UserCanFireHandler; public Action FireHandler; - + public ServerRangedBarrelComponent Barrel { get => _barrel; @@ -95,7 +96,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged { return; } - + var curTime = IoCManager.Resolve().CurTime; var span = curTime - _lastFireTime; if (span.TotalSeconds < 1 / _barrel.FireRate) diff --git a/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs b/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs index b02225e97d..ad5c232c9c 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Content.Server.AI.Utility.AiLogic; using Content.Server.GameObjects.Components.Movement; -using Content.Server.Interfaces.GameObjects.Components.Movement; +using Content.Shared.GameObjects.Components.Movement; using JetBrains.Annotations; using Robust.Server.AI; using Robust.Server.Interfaces.Console; diff --git a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs index 0bf0b323f6..e9c34ee2d9 100644 --- a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs @@ -1,58 +1,44 @@ -using System; -using Content.Server.GameObjects.Components; +using Content.Server.GameObjects.Components; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Movement; using Content.Server.GameObjects.Components.Sound; -using Content.Server.Interfaces.GameObjects.Components.Movement; using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Movement; -using Content.Shared.Input; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Maps; using Content.Shared.Physics; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; -using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Timing; -using Robust.Shared.Configuration; -using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Components.Transform; -using Robust.Shared.GameObjects.Systems; -using Robust.Shared.Input; -using Robust.Shared.Input.Binding; -using Robust.Shared.Interfaces.Configuration; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.Map; -using Robust.Shared.Interfaces.Physics; using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Map; -using Robust.Shared.Maths; -using Robust.Shared.Players; +using Robust.Shared.Physics; using Robust.Shared.Prototypes; using Robust.Shared.Random; +#nullable enable + namespace Content.Server.GameObjects.EntitySystems { [UsedImplicitly] - internal class MoverSystem : EntitySystem + internal class MoverSystem : SharedMoverSystem { #pragma warning disable 649 - [Dependency] private readonly IPauseManager _pauseManager; - [Dependency] private readonly IPrototypeManager _prototypeManager; - [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager; - [Dependency] private readonly IMapManager _mapManager; - [Dependency] private readonly IRobustRandom _robustRandom; - [Dependency] private readonly IConfigurationManager _configurationManager; - [Dependency] private readonly IEntityManager _entityManager; - [Dependency] private readonly IPhysicsManager _physicsManager; + [Dependency] private readonly IPauseManager _pauseManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IRobustRandom _robustRandom = default!; #pragma warning restore 649 - private AudioSystem _audioSystem; + private AudioSystem _audioSystem = default!; private const float StepSoundMoveDistanceRunning = 2; private const float StepSoundMoveDistanceWalking = 1.5f; @@ -60,40 +46,41 @@ namespace Content.Server.GameObjects.EntitySystems /// public override void Initialize() { - EntityQuery = new TypeEntityQuery(typeof(IMoverComponent)); - - var moveUpCmdHandler = InputCmdHandler.FromDelegate( - session => HandleDirChange(session, Direction.North, true), - session => HandleDirChange(session, Direction.North, false)); - var moveLeftCmdHandler = InputCmdHandler.FromDelegate( - session => HandleDirChange(session, Direction.West, true), - session => HandleDirChange(session, Direction.West, false)); - var moveRightCmdHandler = InputCmdHandler.FromDelegate( - session => HandleDirChange(session, Direction.East, true), - session => HandleDirChange(session, Direction.East, false)); - var moveDownCmdHandler = InputCmdHandler.FromDelegate( - session => HandleDirChange(session, Direction.South, true), - session => HandleDirChange(session, Direction.South, false)); - var walkCmdHandler = InputCmdHandler.FromDelegate( - session => HandleRunChange(session, true), - session => HandleRunChange(session, false)); - - var input = EntitySystemManager.GetEntitySystem(); - - CommandBinds.Builder - .Bind(EngineKeyFunctions.MoveUp, moveUpCmdHandler) - .Bind(EngineKeyFunctions.MoveLeft, moveLeftCmdHandler) - .Bind(EngineKeyFunctions.MoveRight, moveRightCmdHandler) - .Bind(EngineKeyFunctions.MoveDown, moveDownCmdHandler) - .Bind(EngineKeyFunctions.Walk, walkCmdHandler) - .Register(); + base.Initialize(); SubscribeLocalEvent(PlayerAttached); SubscribeLocalEvent(PlayerDetached); _audioSystem = EntitySystemManager.GetEntitySystem(); - _configurationManager.RegisterCVar("game.diagonalmovement", true, CVar.ARCHIVE); + UpdatesBefore.Add(typeof(PhysicsSystem)); + } + + public override void Update(float frameTime) + { + foreach (var entity in RelevantEntities) + { + if (_pauseManager.IsEntityPaused(entity)) + { + continue; + } + + var mover = entity.GetComponent(); + var physics = entity.GetComponent(); + if (entity.TryGetComponent(out var collider)) + { + UpdateKinematics(entity.Transform, mover, physics, collider); + } + else + { + UpdateKinematics(entity.Transform, mover, physics); + } + } + } + + protected override void SetController(SharedPhysicsComponent physics) + { + ((PhysicsComponent) physics).SetController(); } private static void PlayerAttached(PlayerAttachSystemMessage ev) @@ -112,185 +99,50 @@ namespace Content.Server.GameObjects.EntitySystems } } - /// - public override void Shutdown() + protected override void HandleFootsteps(IMoverComponent mover) { - CommandBinds.Unregister(); - base.Shutdown(); - } - - /// - public override void Update(float frameTime) - { - foreach (var entity in RelevantEntities) + var transform = mover.Owner.Transform; + // Handle footsteps. + if (_mapManager.GridExists(mover.LastPosition.GridID)) { - if (_pauseManager.IsEntityPaused(entity)) - { - continue; - } - var mover = entity.GetComponent(); - var physics = entity.GetComponent(); - if (entity.TryGetComponent(out var collider)) - { - UpdateKinematics(entity.Transform, mover, physics, frameTime, collider); - } - else - { - UpdateKinematics(entity.Transform, mover, physics, frameTime); - } - } - } - - private void UpdateKinematics(ITransformComponent transform, IMoverComponent mover, PhysicsComponent physics, float frameTime, CollidableComponent collider = null) - { - if (physics.Controller == null) - { - // Set up controller - physics.SetController(); + // Can happen when teleporting between grids. + var distance = transform.GridPosition.Distance(_mapManager, mover.LastPosition); + mover.StepSoundDistance += distance; } - var weightless = !transform.Owner.HasComponent() && - _physicsManager.IsWeightless(transform.GridPosition); - - if (weightless && collider != null) + mover.LastPosition = transform.GridPosition; + float distanceNeeded; + if (mover.Sprinting) { - // No gravity: is our entity touching anything? - var touching = IsAroundCollider(transform, mover, collider); - - if (!touching) - { - return; - } - } - - if (mover.VelocityDir.LengthSquared < 0.001 || !ActionBlockerSystem.CanMove(mover.Owner) && !weightless) - { - (physics.Controller as MoverController)?.StopMoving(); + distanceNeeded = StepSoundMoveDistanceRunning; } else { - if (weightless) + distanceNeeded = StepSoundMoveDistanceWalking; + } + + if (mover.StepSoundDistance > distanceNeeded) + { + mover.StepSoundDistance = 0; + + if (!mover.Owner.HasComponent()) { - (physics.Controller as MoverController)?.Push(mover.VelocityDir, mover.CurrentPushSpeed); - transform.LocalRotation = mover.VelocityDir.GetDir().ToAngle(); return; } - (physics.Controller as MoverController)?.Move(mover.VelocityDir, - mover.Sprinting ? mover.CurrentSprintSpeed : mover.CurrentWalkSpeed); - transform.LocalRotation = mover.VelocityDir.GetDir().ToAngle(); - // Handle footsteps. - if (_mapManager.GridExists(mover.LastPosition.GridID)) + if (mover.Owner.TryGetComponent(out var inventory) + && inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.SHOES, out var item) + && item.Owner.TryGetComponent(out var modifier)) { - // Can happen when teleporting between grids. - var distance = transform.GridPosition.Distance(_mapManager, mover.LastPosition); - mover.StepSoundDistance += distance; - } - - mover.LastPosition = transform.GridPosition; - float distanceNeeded; - if (mover.Sprinting) - { - distanceNeeded = StepSoundMoveDistanceRunning; + modifier.PlayFootstep(); } else { - distanceNeeded = StepSoundMoveDistanceWalking; - } - if (mover.StepSoundDistance > distanceNeeded) - { - mover.StepSoundDistance = 0; - - if (!mover.Owner.HasComponent()) - { - return; - } - - if (mover.Owner.TryGetComponent(out var inventory) - && inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.SHOES, out var item) - && item.Owner.TryGetComponent(out var modifier)) - { - modifier.PlayFootstep(); - } - else - { - PlayFootstepSound(transform.GridPosition); - } + PlayFootstepSound(transform.GridPosition); } } } - private bool IsAroundCollider(ITransformComponent transform, IMoverComponent mover, CollidableComponent collider) - { - foreach (var entity in _entityManager.GetEntitiesInRange(transform.Owner, mover.GrabRange, true)) - { - if (entity == transform.Owner) - { - continue; // Don't try to push off of yourself! - } - - if (!entity.TryGetComponent(out var otherCollider)) - { - continue; - } - - var touching = ((collider.CollisionMask & otherCollider.CollisionLayer) != 0x0 - || (otherCollider.CollisionMask & collider.CollisionLayer) != 0x0) // Ensure collision - && !entity.HasComponent(); // This can't be an item - - if (touching) - { - return true; - } - } - - return false; - } - - private static void HandleDirChange(ICommonSession session, Direction dir, bool state) - { - var playerSes = session as IPlayerSession; - if (!TryGetAttachedComponent(playerSes, out IMoverComponent moverComp)) - return; - - var owner = playerSes?.AttachedEntity; - - if (owner != null) - { - foreach (var comp in owner.GetAllComponents()) - { - comp.MoveInputPressed(playerSes); - } - } - - moverComp.SetVelocityDirection(dir, state); - } - - private static void HandleRunChange(ICommonSession session, bool walking) - { - if (!TryGetAttachedComponent(session as IPlayerSession, out PlayerInputMoverComponent moverComp)) - return; - - moverComp.Sprinting = !walking; - } - - private static bool TryGetAttachedComponent(IPlayerSession session, out T component) - where T : IComponent - { - component = default; - - var ent = session.AttachedEntity; - - if (ent == null || !ent.IsValid()) - return false; - - if (!ent.TryGetComponent(out T comp)) - return false; - - component = comp; - return true; - } - private void PlayFootstepSound(GridCoordinates coordinates) { // Step one: figure out sound collection prototype. @@ -317,12 +169,13 @@ namespace Content.Server.GameObjects.EntitySystems else { // Walking on a tile. - var def = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId]; + var def = (ContentTileDefinition) _tileDefinitionManager[tile.Tile.TypeId]; if (def.FootstepSounds == null) { // Nothing to play, oh well. return; } + soundCollectionName = def.FootstepSounds; } diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index 14d6225851..341106539f 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Content.Server.GameObjects; +using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.EntitySystemMessages; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Server/Interfaces/GameObjects/Components/Movement/IRelayMoveInput.cs b/Content.Server/Interfaces/GameObjects/Components/Movement/IRelayMoveInput.cs deleted file mode 100644 index 53df4ed7e1..0000000000 --- a/Content.Server/Interfaces/GameObjects/Components/Movement/IRelayMoveInput.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Server.Interfaces.Player; - -namespace Content.Server.Interfaces.GameObjects.Components.Movement -{ - public interface IRelayMoveInput - { - void MoveInputPressed(IPlayerSession session); - } -} diff --git a/Content.Server/Throw/ThrowHelper.cs b/Content.Server/Throw/ThrowHelper.cs index 7cb7a272bf..cc04d18ef6 100644 --- a/Content.Server/Throw/ThrowHelper.cs +++ b/Content.Server/Throw/ThrowHelper.cs @@ -148,9 +148,10 @@ namespace Content.Server.Throw var velocityNecessary = distance / throwDuration; var impulseNecessary = velocityNecessary * mass; + var forceNecessary = impulseNecessary * (1f / timing.TickRate); // Then clamp it to the max force allowed and call Throw(). - Throw(thrownEnt, MathF.Min(impulseNecessary, throwForceMax), targetLoc, sourceLoc, spread, throwSourceEnt); + Throw(thrownEnt, MathF.Min(forceNecessary, throwForceMax), targetLoc, sourceLoc, spread, throwSourceEnt); } } } diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedStunnableComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedStunnableComponent.cs new file mode 100644 index 0000000000..121b1d0e74 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Mobs/SharedStunnableComponent.cs @@ -0,0 +1,71 @@ +using System; +using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.GameObjects.Components.Mobs +{ + public abstract class SharedStunnableComponent : Component, IMoveSpeedModifier, IActionBlocker + { + public sealed override string Name => "Stunnable"; + public override uint? NetID => ContentNetIDs.STUNNABLE; + + [ViewVariables] protected float WalkModifierOverride = 0f; + [ViewVariables] protected float RunModifierOverride = 0f; + + [ViewVariables] public abstract bool Stunned { get; } + [ViewVariables] public abstract bool KnockedDown { get; } + [ViewVariables] public abstract bool SlowedDown { get; } + + #region ActionBlockers + public bool CanMove() => (!Stunned); + + public bool CanInteract() => (!Stunned); + + public bool CanUse() => (!Stunned); + + public bool CanThrow() => (!Stunned); + + public bool CanSpeak() => true; + + public bool CanDrop() => (!Stunned); + + public bool CanPickup() => (!Stunned); + + public bool CanEmote() => true; + + public bool CanAttack() => (!Stunned); + + public bool CanEquip() => (!Stunned); + + public bool CanUnequip() => (!Stunned); + public bool CanChangeDirection() => true; + #endregion + + [ViewVariables] + public float WalkSpeedModifier => (SlowedDown ? (WalkModifierOverride <= 0f ? 0.5f : WalkModifierOverride) : 1f); + [ViewVariables] + public float SprintSpeedModifier => (SlowedDown ? (RunModifierOverride <= 0f ? 0.5f : RunModifierOverride) : 1f); + + [Serializable, NetSerializable] + protected sealed class StunnableComponentState : ComponentState + { + public bool Stunned { get; } + public bool KnockedDown { get; } + public bool SlowedDown { get; } + public float WalkModifierOverride { get; } + public float RunModifierOverride { get; } + + public StunnableComponentState(bool stunned, bool knockedDown, bool slowedDown, float walkModifierOverride, float runModifierOverride) : base(ContentNetIDs.STUNNABLE) + { + Stunned = stunned; + KnockedDown = knockedDown; + SlowedDown = slowedDown; + WalkModifierOverride = walkModifierOverride; + RunModifierOverride = runModifierOverride; + } + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Movement/IMoverComponent.cs b/Content.Shared/GameObjects/Components/Movement/IMoverComponent.cs similarity index 81% rename from Content.Server/Interfaces/GameObjects/Components/Movement/IMoverComponent.cs rename to Content.Shared/GameObjects/Components/Movement/IMoverComponent.cs index 9a5196ad3f..3074a970fd 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Movement/IMoverComponent.cs +++ b/Content.Shared/GameObjects/Components/Movement/IMoverComponent.cs @@ -1,9 +1,8 @@ -using Content.Server.GameObjects.Components.Movement; -using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Map; using Robust.Shared.Maths; -namespace Content.Server.Interfaces.GameObjects.Components.Movement +namespace Content.Shared.GameObjects.Components.Movement { // Does nothing except ensure uniqueness between mover components. // There can only be one. @@ -33,12 +32,12 @@ namespace Content.Server.Interfaces.GameObjects.Components.Movement /// /// Is the entity Sprinting (running)? /// - bool Sprinting { get; set; } + bool Sprinting { get; } /// /// Calculated linear velocity direction of the entity. /// - Vector2 VelocityDir { get; } + (Vector2 walking, Vector2 sprinting) VelocityDir { get; } GridCoordinates LastPosition { get; set; } @@ -50,7 +49,11 @@ namespace Content.Server.Interfaces.GameObjects.Components.Movement /// opposite directions will cancel each other out, resulting in no direction. /// /// Direction to toggle. + /// /// If the direction is active. - void SetVelocityDirection(Direction direction, bool enabled); + void SetVelocityDirection(Direction direction, ushort subTick, bool enabled); + + void SetSprinting(ushort subTick, bool walking); + } } diff --git a/Content.Shared/GameObjects/Components/Movement/IRelayMoveInput.cs b/Content.Shared/GameObjects/Components/Movement/IRelayMoveInput.cs new file mode 100644 index 0000000000..433102afd4 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Movement/IRelayMoveInput.cs @@ -0,0 +1,9 @@ +using Robust.Shared.Players; + +namespace Content.Shared.GameObjects.Components.Movement +{ + public interface IRelayMoveInput + { + void MoveInputPressed(ICommonSession session); + } +} diff --git a/Content.Server/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs b/Content.Shared/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs similarity index 96% rename from Content.Server/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs rename to Content.Shared/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs index 738884f463..cdc70f8435 100644 --- a/Content.Server/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs +++ b/Content.Shared/GameObjects/Components/Movement/MovementSpeedModifierComponent.cs @@ -1,9 +1,8 @@ - using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; -namespace Content.Server.GameObjects.Components.Movement +namespace Content.Shared.GameObjects.Components.Movement { [RegisterComponent] public class MovementSpeedModifierComponent : Component @@ -85,7 +84,7 @@ namespace Content.Server.GameObjects.Components.Movement } } - interface IMoveSpeedModifier + public interface IMoveSpeedModifier { float WalkSpeedModifier { get; } float SprintSpeedModifier { get; } diff --git a/Content.Shared/GameObjects/Components/Movement/SharedPlayerInputMoverComponent.cs b/Content.Shared/GameObjects/Components/Movement/SharedPlayerInputMoverComponent.cs new file mode 100644 index 0000000000..74664e9fa2 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Movement/SharedPlayerInputMoverComponent.cs @@ -0,0 +1,295 @@ +using System; +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components; +using Robust.Shared.Interfaces.Configuration; +using Robust.Shared.Interfaces.Timing; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Map; +using Robust.Shared.Maths; +using Robust.Shared.Physics; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; +using Robust.Shared.ViewVariables; + +#nullable enable + +namespace Content.Shared.GameObjects.Components.Movement +{ + public abstract class SharedPlayerInputMoverComponent : Component, IMoverComponent, ICollideSpecial + { + // This class has to be able to handle server TPS being lower than client FPS. + // While still having perfectly responsive movement client side. + // We do this by keeping track of the exact sub-tick values that inputs are pressed on the client, + // and then building a total movement vector based on those sub-tick steps. + // + // We keep track of the last sub-tick a movement input came in, + // Then when a new input comes in, we calculate the fraction of the tick the LAST input was active for + // (new sub-tick - last sub-tick) + // and then add to the total-this-tick movement vector + // by multiplying that fraction by the movement direction for the last input. + // This allows us to incrementally build the movement vector for the current tick, + // without having to keep track of some kind of list of inputs and calculating it later. + // + // We have to keep track of a separate movement vector for walking and sprinting, + // since we don't actually know our current movement speed while processing inputs. + // We change which vector we write into based on whether we were sprinting after the previous input. + // (well maybe we do but the code is designed such that MoverSystem applies movement speed) + // (and I'm not changing that) + + [Dependency] private readonly IConfigurationManager _configurationManager = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + + public sealed override string Name => "PlayerInputMover"; + public sealed override uint? NetID => ContentNetIDs.PLAYER_INPUT_MOVER; + + private GameTick _lastInputTick; + private ushort _lastInputSubTick; + private Vector2 _curTickWalkMovement; + private Vector2 _curTickSprintMovement; + + private MoveButtons _heldMoveButtons = MoveButtons.None; + + public float CurrentWalkSpeed + { + get + { + if (Owner.TryGetComponent(out MovementSpeedModifierComponent component)) + { + return component.CurrentWalkSpeed; + } + + return MovementSpeedModifierComponent.DefaultBaseWalkSpeed; + } + } + + public float CurrentSprintSpeed + { + get + { + if (Owner.TryGetComponent(out MovementSpeedModifierComponent component)) + { + return component.CurrentSprintSpeed; + } + + return MovementSpeedModifierComponent.DefaultBaseSprintSpeed; + } + } + + public float CurrentPushSpeed => 5; + public float GrabRange => 0.2f; + public bool Sprinting => !_heldMoveButtons.HasFlag(MoveButtons.Walk); + + /// + /// Calculated linear velocity direction of the entity. + /// + [ViewVariables] + public (Vector2 walking, Vector2 sprinting) VelocityDir + { + get + { + if (!_gameTiming.InSimulation) + { + // Outside of simulation we'll be running client predicted movement per-frame. + // So return a full-length vector as if it's a full tick. + // Physics system will have the correct time step anyways. + var immediateDir = DirVecForButtons(_heldMoveButtons); + return Sprinting ? (Vector2.Zero, immediateDir) : (immediateDir, Vector2.Zero); + } + + Vector2 walk; + Vector2 sprint; + float remainingFraction; + + if (_gameTiming.CurTick > _lastInputTick) + { + walk = Vector2.Zero; + sprint = Vector2.Zero; + remainingFraction = 1; + } + else + { + walk = _curTickWalkMovement; + sprint = _curTickSprintMovement; + remainingFraction = (ushort.MaxValue - _lastInputSubTick) / (float) ushort.MaxValue; + } + + var curDir = DirVecForButtons(_heldMoveButtons) * remainingFraction; + + if (Sprinting) + { + sprint += curDir; + } + else + { + walk += curDir; + } + + // Logger.Info($"{curDir}{walk}{sprint}"); + return (walk, sprint); + } + } + + public abstract GridCoordinates LastPosition { get; set; } + public abstract float StepSoundDistance { get; set; } + + /// + /// Whether or not the player can move diagonally. + /// + [ViewVariables] + public bool DiagonalMovementEnabled => _configurationManager.GetCVar("game.diagonalmovement"); + + /// + public override void OnAdd() + { + // This component requires that the entity has a PhysicsComponent. + if (!Owner.HasComponent()) + Logger.Error( + $"[ECS] {Owner.Prototype?.Name} - {nameof(SharedPlayerInputMoverComponent)} requires" + + $" {nameof(SharedPhysicsComponent)}. "); + + base.OnAdd(); + } + + + /// + /// Toggles one of the four cardinal directions. Each of the four directions are + /// composed into a single direction vector, . Enabling + /// opposite directions will cancel each other out, resulting in no direction. + /// + /// Direction to toggle. + /// + /// If the direction is active. + public void SetVelocityDirection(Direction direction, ushort subTick, bool enabled) + { + // Logger.Info($"[{_gameTiming.CurTick}/{subTick}] {direction}: {enabled}"); + + var bit = direction switch + { + Direction.East => MoveButtons.Right, + Direction.North => MoveButtons.Up, + Direction.West => MoveButtons.Left, + Direction.South => MoveButtons.Down, + _ => throw new ArgumentException(nameof(direction)) + }; + + SetMoveInput(subTick, enabled, bit); + } + + private void SetMoveInput(ushort subTick, bool enabled, MoveButtons bit) + { + // Modifies held state of a movement button at a certain sub tick and updates current tick movement vectors. + + if (_gameTiming.CurTick > _lastInputTick) + { + _curTickWalkMovement = Vector2.Zero; + _curTickSprintMovement = Vector2.Zero; + _lastInputTick = _gameTiming.CurTick; + _lastInputSubTick = 0; + } + + var fraction = (subTick - _lastInputSubTick) / (float) ushort.MaxValue; + + ref var lastMoveAmount = ref Sprinting ? ref _curTickSprintMovement : ref _curTickWalkMovement; + + lastMoveAmount += DirVecForButtons(_heldMoveButtons) * fraction; + + if (enabled) + { + _heldMoveButtons |= bit; + } + else + { + _heldMoveButtons &= ~bit; + } + + _lastInputSubTick = subTick; + + Dirty(); + } + + public void SetSprinting(ushort subTick, bool walking) + { + // Logger.Info($"[{_gameTiming.CurTick}/{subTick}] Sprint: {enabled}"); + + SetMoveInput(subTick, walking, MoveButtons.Walk); + } + + public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) + { + if (curState is MoverComponentState state) + { + _heldMoveButtons = state.Buttons; + _lastInputTick = GameTick.Zero; + _lastInputSubTick = 0; + } + } + + public override ComponentState GetComponentState() + { + return new MoverComponentState(_heldMoveButtons); + } + + /// + /// Retrieves the normalized direction vector for a specified combination of movement keys. + /// + private Vector2 DirVecForButtons(MoveButtons buttons) + { + // key directions are in screen coordinates + // _moveDir is in world coordinates + // if the camera is moved, this needs to be changed + + var x = 0; + x -= buttons.HasFlag(MoveButtons.Left) ? 1 : 0; + x += buttons.HasFlag(MoveButtons.Right) ? 1 : 0; + + var y = 0; + if (DiagonalMovementEnabled || x == 0) + { + y -= buttons.HasFlag(MoveButtons.Down) ? 1 : 0; + y += buttons.HasFlag(MoveButtons.Up) ? 1 : 0; + } + + var vec = new Vector2(x, y); + + // can't normalize zero length vector + if (vec.LengthSquared > 1.0e-6) + { + // Normalize so that diagonals aren't faster or something. + vec = vec.Normalized; + } + + return vec; + } + + bool ICollideSpecial.PreventCollide(IPhysBody collidedWith) + { + // Don't collide with other mobs + return collidedWith.Owner.HasComponent(); + } + + [Serializable, NetSerializable] + private sealed class MoverComponentState : ComponentState + { + public MoveButtons Buttons { get; } + + public MoverComponentState(MoveButtons buttons) : base(ContentNetIDs + .PLAYER_INPUT_MOVER) + { + Buttons = buttons; + } + } + + [Flags] + private enum MoveButtons : byte + { + None = 0, + Up = 1, + Down = 2, + Left = 4, + Right = 8, + Walk = 16, + } + } +} diff --git a/Content.Shared/GameObjects/Components/Nutrition/SharedHungerComponent.cs b/Content.Shared/GameObjects/Components/Nutrition/SharedHungerComponent.cs new file mode 100644 index 0000000000..7faa1d69a6 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Nutrition/SharedHungerComponent.cs @@ -0,0 +1,60 @@ +using System; +using Content.Shared.GameObjects.Components.Movement; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Nutrition +{ + public abstract class SharedHungerComponent : Component, IMoveSpeedModifier + { + public sealed override string Name => "Hunger"; + + public sealed override uint? NetID => ContentNetIDs.HUNGER; + + public abstract HungerThreshold CurrentHungerThreshold { get; } + + + float IMoveSpeedModifier.WalkSpeedModifier + { + get + { + if (CurrentHungerThreshold == HungerThreshold.Starving) + { + return 0.5f; + } + return 1.0f; + } + } + float IMoveSpeedModifier.SprintSpeedModifier + { + get + { + if (CurrentHungerThreshold == HungerThreshold.Starving) + { + return 0.5f; + } + return 1.0f; + } + } + + [Serializable, NetSerializable] + protected sealed class HungerComponentState : ComponentState + { + public HungerThreshold CurrentThreshold { get; } + + public HungerComponentState(HungerThreshold currentThreshold) : base(ContentNetIDs.HUNGER) + { + CurrentThreshold = currentThreshold; + } + } + } + + public enum HungerThreshold : byte + { + Overfed, + Okay, + Peckish, + Starving, + Dead, + } +} diff --git a/Content.Shared/GameObjects/Components/Nutrition/SharedThirstComponent.cs b/Content.Shared/GameObjects/Components/Nutrition/SharedThirstComponent.cs new file mode 100644 index 0000000000..70ad6d4976 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Nutrition/SharedThirstComponent.cs @@ -0,0 +1,61 @@ +using System; +using Content.Shared.GameObjects.Components.Movement; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Nutrition +{ + public abstract class SharedThirstComponent : Component, IMoveSpeedModifier + { + public sealed override string Name => "Thirst"; + + public sealed override uint? NetID => ContentNetIDs.THIRST; + + public abstract ThirstThreshold CurrentThirstThreshold { get; } + + float IMoveSpeedModifier.SprintSpeedModifier + { + get + { + if (CurrentThirstThreshold == ThirstThreshold.Parched) + { + return 0.25f; + } + return 1.0f; + } + } + float IMoveSpeedModifier.WalkSpeedModifier + { + get + { + if (CurrentThirstThreshold == ThirstThreshold.Parched) + { + return 0.5f; + } + return 1.0f; + } + } + + [Serializable, NetSerializable] + protected sealed class ThirstComponentState : ComponentState + { + public ThirstThreshold CurrentThreshold { get; } + + public ThirstComponentState(ThirstThreshold currentThreshold) : base(ContentNetIDs.THIRST) + { + CurrentThreshold = currentThreshold; + } + } + + } + + public enum ThirstThreshold : byte + { + // Hydrohomies + OverHydrated, + Okay, + Thirsty, + Parched, + Dead, + } +} diff --git a/Content.Shared/GameObjects/Components/Observer/SharedGhostComponent.cs b/Content.Shared/GameObjects/Components/Observer/SharedGhostComponent.cs index b838c3b63e..771c0b0b6f 100644 --- a/Content.Shared/GameObjects/Components/Observer/SharedGhostComponent.cs +++ b/Content.Shared/GameObjects/Components/Observer/SharedGhostComponent.cs @@ -1,13 +1,22 @@ using System; +using Content.Shared.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; namespace Content.Shared.GameObjects.Components.Observer { - public class SharedGhostComponent : Component + public class SharedGhostComponent : Component, IActionBlocker { public override string Name => "Ghost"; public override uint? NetID => ContentNetIDs.GHOST; + + public bool CanInteract() => false; + public bool CanUse() => false; + public bool CanThrow() => false; + public bool CanDrop() => false; + public bool CanPickup() => false; + public bool CanEmote() => false; + public bool CanAttack() => false; } [Serializable, NetSerializable] diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index 5cac42d0d2..2fc90dbae7 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -50,8 +50,13 @@ public const uint PDA = 1044; public const uint PATHFINDER_DEBUG = 1045; public const uint AI_DEBUG = 1046; - public const uint FLASHABLE = 1047; - + public const uint PLAYER_INPUT_MOVER = 1047; + public const uint STUNNABLE = 1048; + public const uint HUNGER = 1049; + public const uint THIRST = 1050; + + public const uint FLASHABLE = 1051; + // Net IDs for integration tests. public const uint PREDICTION_TEST = 10001; } diff --git a/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs b/Content.Shared/GameObjects/EntitySystems/ActionBlockerSystem.cs similarity index 98% rename from Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs rename to Content.Shared/GameObjects/EntitySystems/ActionBlockerSystem.cs index 90bb573228..d22f5ebace 100644 --- a/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs +++ b/Content.Shared/GameObjects/EntitySystems/ActionBlockerSystem.cs @@ -1,7 +1,7 @@ using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Shared.GameObjects.EntitySystems { public interface IActionBlocker { diff --git a/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs b/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs new file mode 100644 index 0000000000..740dddf9ea --- /dev/null +++ b/Content.Shared/GameObjects/EntitySystems/SharedMoverSystem.cs @@ -0,0 +1,227 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared.GameObjects.Components.Movement; +using Content.Shared.Physics; +using Robust.Shared.Configuration; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Input; +using Robust.Shared.Input.Binding; +using Robust.Shared.Interfaces.Configuration; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.Interfaces.Physics; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Physics; +using Robust.Shared.Players; + +#nullable enable + +namespace Content.Shared.GameObjects.EntitySystems +{ + public abstract class SharedMoverSystem : EntitySystem + { + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IPhysicsManager _physicsManager = default!; + [Dependency] private readonly IConfigurationManager _configurationManager = default!; + + public override void Initialize() + { + base.Initialize(); + + EntityQuery = new TypeEntityQuery(typeof(IMoverComponent)); + + var moveUpCmdHandler = new MoverDirInputCmdHandler(Direction.North); + var moveLeftCmdHandler = new MoverDirInputCmdHandler(Direction.West); + var moveRightCmdHandler = new MoverDirInputCmdHandler(Direction.East); + var moveDownCmdHandler = new MoverDirInputCmdHandler(Direction.South); + + CommandBinds.Builder + .Bind(EngineKeyFunctions.MoveUp, moveUpCmdHandler) + .Bind(EngineKeyFunctions.MoveLeft, moveLeftCmdHandler) + .Bind(EngineKeyFunctions.MoveRight, moveRightCmdHandler) + .Bind(EngineKeyFunctions.MoveDown, moveDownCmdHandler) + .Bind(EngineKeyFunctions.Walk, new WalkInputCmdHandler()) + .Register(); + + _configurationManager.RegisterCVar("game.diagonalmovement", true, CVar.ARCHIVE); + } + + /// + public override void Shutdown() + { + CommandBinds.Unregister(); + base.Shutdown(); + } + + + protected void UpdateKinematics(ITransformComponent transform, IMoverComponent mover, SharedPhysicsComponent physics, + CollidableComponent? collider = null) + { + if (physics.Controller == null) + { + // Set up controller + SetController(physics); + } + + var weightless = !transform.Owner.HasComponent() && + _physicsManager.IsWeightless(transform.GridPosition); + + if (weightless && collider != null) + { + // No gravity: is our entity touching anything? + var touching = IsAroundCollider(transform, mover, collider); + + if (!touching) + { + return; + } + } + + // TODO: movement check. + var (walkDir, sprintDir) = mover.VelocityDir; + var combined = walkDir + sprintDir; + if (combined.LengthSquared < 0.001 || !ActionBlockerSystem.CanMove(mover.Owner) && !weightless) + { + (physics.Controller as MoverController)?.StopMoving(); + } + else + { + //Console.WriteLine($"{IoCManager.Resolve().TickStamp}: {combined}"); + + if (weightless) + { + (physics.Controller as MoverController)?.Push(combined, mover.CurrentPushSpeed); + transform.LocalRotation = walkDir.GetDir().ToAngle(); + return; + } + + var total = walkDir * mover.CurrentWalkSpeed + sprintDir * mover.CurrentSprintSpeed; + //Console.WriteLine($"{walkDir} ({mover.CurrentWalkSpeed}) + {sprintDir} ({mover.CurrentSprintSpeed}): {total}"); + + (physics.Controller as MoverController)?.Move(total, 1); + transform.LocalRotation = total.GetDir().ToAngle(); + + HandleFootsteps(mover); + } + } + + protected virtual void HandleFootsteps(IMoverComponent mover) + { + + } + + protected abstract void SetController(SharedPhysicsComponent physics); + + private bool IsAroundCollider(ITransformComponent transform, IMoverComponent mover, + CollidableComponent collider) + { + foreach (var entity in _entityManager.GetEntitiesInRange(transform.Owner, mover.GrabRange, true)) + { + if (entity == transform.Owner) + { + continue; // Don't try to push off of yourself! + } + + if (!entity.TryGetComponent(out var otherCollider)) + { + continue; + } + + // TODO: Item check. + var touching = ((collider.CollisionMask & otherCollider.CollisionLayer) != 0x0 + || (otherCollider.CollisionMask & collider.CollisionLayer) != 0x0) // Ensure collision + && true; // !entity.HasComponent(); // This can't be an item + + if (touching) + { + return true; + } + } + + return false; + } + + + private static void HandleDirChange(ICommonSession? session, Direction dir, ushort subTick, bool state) + { + if (!TryGetAttachedComponent(session, out var moverComp)) + return; + + var owner = session?.AttachedEntity; + + if (owner != null) + { + foreach (var comp in owner.GetAllComponents()) + { + comp.MoveInputPressed(session); + } + } + + moverComp.SetVelocityDirection(dir, subTick, state); + } + + private static void HandleRunChange(ICommonSession? session, ushort subTick, bool walking) + { + if (!TryGetAttachedComponent(session, out var moverComp)) + { + return; + } + + moverComp.SetSprinting(subTick, walking); + } + + private static bool TryGetAttachedComponent(ICommonSession? session, [MaybeNullWhen(false)] out T component) + where T : IComponent + { + component = default; + + var ent = session?.AttachedEntity; + + if (ent == null || !ent.IsValid()) + return false; + + if (!ent.TryGetComponent(out T comp)) + return false; + + component = comp; + return true; + } + + private sealed class MoverDirInputCmdHandler : InputCmdHandler + { + private readonly Direction _dir; + + public MoverDirInputCmdHandler(Direction dir) + { + _dir = dir; + } + + public override bool HandleCmdMessage(ICommonSession? session, InputCmdMessage message) + { + if (!(message is FullInputCmdMessage full)) + { + return false; + } + + HandleDirChange(session, _dir, message.SubTick, full.State == BoundKeyState.Down); + return false; + } + } + + private sealed class WalkInputCmdHandler : InputCmdHandler + { + public override bool HandleCmdMessage(ICommonSession? session, InputCmdMessage message) + { + if (!(message is FullInputCmdMessage full)) + { + return false; + } + + HandleRunChange(session, full.SubTick, full.State == BoundKeyState.Down); + return false; + } + } + } +}