diff --git a/Content.Client/Gravity/GravitySystem.Shake.cs b/Content.Client/Gravity/GravitySystem.Shake.cs new file mode 100644 index 0000000000..60307b619b --- /dev/null +++ b/Content.Client/Gravity/GravitySystem.Shake.cs @@ -0,0 +1,59 @@ +using Content.Shared.Camera; +using Content.Shared.Gravity; +using Robust.Client.Player; +using Robust.Shared.Audio; +using Robust.Shared.Player; +using Robust.Shared.Random; + +namespace Content.Client.Gravity; + +public sealed partial class GravitySystem +{ + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!; + + private void InitializeShake() + { + SubscribeLocalEvent(OnShakeInit); + } + + private void OnShakeInit(EntityUid uid, GravityShakeComponent component, ComponentInit args) + { + var localPlayer = _playerManager.LocalPlayer?.ControlledEntity; + + if (!TryComp(localPlayer, out var xform) || + xform.GridUid != uid && xform.MapUid != uid) + { + return; + } + + if (Timing.IsFirstTimePredicted && TryComp(uid, out var gravity)) + { + _audio.PlayGlobal(gravity.GravityShakeSound, Filter.Local(), true, AudioParams.Default.WithVolume(-2f)); + } + } + + protected override void ShakeGrid(EntityUid uid, GravityComponent? gravity = null) + { + base.ShakeGrid(uid, gravity); + + if (!Resolve(uid, ref gravity) || !Timing.IsFirstTimePredicted) + return; + + var localPlayer = _playerManager.LocalPlayer?.ControlledEntity; + + if (!TryComp(localPlayer, out var xform)) + return; + + if (xform.GridUid != uid || + xform.GridUid == null && xform.MapUid != uid) + { + return; + } + + var kick = new Vector2(_random.NextFloat(), _random.NextFloat()) * GravityKick; + _sharedCameraRecoil.KickCamera(localPlayer.Value, kick); + } +} diff --git a/Content.Client/Gravity/GravitySystem.cs b/Content.Client/Gravity/GravitySystem.cs index 3efaa6ff96..346c7d79eb 100644 --- a/Content.Client/Gravity/GravitySystem.cs +++ b/Content.Client/Gravity/GravitySystem.cs @@ -1,9 +1,12 @@ using Content.Shared.Gravity; -namespace Content.Client.Gravity -{ - public sealed class GravitySystem : SharedGravitySystem - { +namespace Content.Client.Gravity; +public sealed partial class GravitySystem : SharedGravitySystem +{ + public override void Initialize() + { + base.Initialize(); + InitializeShake(); } } diff --git a/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs b/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs index caeab3c561..4f02e1dbb0 100644 --- a/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs +++ b/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs @@ -1,6 +1,5 @@ using System.Threading.Tasks; using Content.Server.Gravity; -using Content.Server.Gravity.EntitySystems; using Content.Shared.Alert; using Content.Shared.Coordinates; using NUnit.Framework; diff --git a/Content.Server/Gravity/EntitySystems/GravityShakeSystem.cs b/Content.Server/Gravity/EntitySystems/GravityShakeSystem.cs deleted file mode 100644 index 06a136316c..0000000000 --- a/Content.Server/Gravity/EntitySystems/GravityShakeSystem.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Content.Shared.Camera; -using Content.Shared.Gravity; -using Robust.Server.Player; -using Robust.Shared.Audio; -using Robust.Shared.Map; -using Robust.Shared.Player; -using Robust.Shared.Random; - -namespace Content.Server.Gravity.EntitySystems -{ - /// - /// Handles the grid shake effect used by the gravity generator. - /// - public sealed class GravityShakeSystem : EntitySystem - { - [Dependency] private readonly IPlayerManager _playerManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; - - [Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!; - - private Dictionary _gridsToShake = new(); - - private const float GravityKick = 100.0f; - private const uint ShakeTimes = 10; - - private float _internalTimer; - - public override void Update(float frameTime) - { - if (_gridsToShake.Count > 0) - { - _internalTimer += frameTime; - - if (_internalTimer > 0.2f) - { - // TODO: Could just have clients do this themselves via event and save bandwidth. - ShakeGrids(); - _internalTimer -= 0.2f; - } - } - else - { - _internalTimer = 0.0f; - } - } - - public void ShakeGrid(EntityUid gridId, GravityComponent comp) - { - _gridsToShake[gridId] = ShakeTimes; - - SoundSystem.Play(comp.GravityShakeSound.GetSound(), - Filter.BroadcastGrid(gridId), AudioParams.Default.WithVolume(-2f)); - } - - private void ShakeGrids() - { - // I have to copy this because C# doesn't allow changing collections while they're - // getting enumerated. - var gridsToShake = new Dictionary(_gridsToShake); - foreach (var gridId in _gridsToShake.Keys) - { - if (_gridsToShake[gridId] == 0) - { - gridsToShake.Remove(gridId); - continue; - } - ShakeGrid(gridId); - gridsToShake[gridId] -= 1; - } - - _gridsToShake = gridsToShake; - } - - private void ShakeGrid(EntityUid gridId) - { - foreach (var player in _playerManager.Sessions) - { - if (player.AttachedEntity is not {Valid: true} attached - || EntityManager.GetComponent(attached).GridUid != gridId - || !EntityManager.HasComponent(attached)) - { - continue; - } - - var kick = new Vector2(_random.NextFloat(), _random.NextFloat()) * GravityKick; - _sharedCameraRecoil.KickCamera(player.AttachedEntity.Value, kick); - } - } - } -} diff --git a/Content.Server/Gravity/EntitySystems/GravitySystem.cs b/Content.Server/Gravity/EntitySystems/GravitySystem.cs deleted file mode 100644 index d1ecabc370..0000000000 --- a/Content.Server/Gravity/EntitySystems/GravitySystem.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Content.Shared.Gravity; -using JetBrains.Annotations; - -namespace Content.Server.Gravity.EntitySystems -{ - [UsedImplicitly] - public sealed class GravitySystem : SharedGravitySystem - { - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnGravityInit); - SubscribeLocalEvent(OnGravityShutdown); - } - - private void OnGravityInit(EntityUid uid, GravityComponent component, ComponentInit args) - { - // Incase there's already a generator on the grid we'll just set it now. - var gridId = Transform(component.Owner).GridUid; - - if (gridId == null) - return; - - GravityChangedEvent message; - - foreach (var generator in EntityManager.EntityQuery()) - { - if (Transform(generator.Owner).GridUid == gridId && generator.GravityActive) - { - component.Enabled = true; - message = new GravityChangedEvent(gridId.Value, true); - RaiseLocalEvent(message); - return; - } - } - - component.Enabled = false; - message = new GravityChangedEvent(gridId.Value, false); - RaiseLocalEvent(message); - } - - private void OnGravityShutdown(EntityUid uid, GravityComponent component, ComponentShutdown args) - { - DisableGravity(component); - } - - public void EnableGravity(GravityComponent comp) - { - if (comp.Enabled) - return; - - var gridId = Transform(comp.Owner).GridUid; - Dirty(comp); - - if (gridId == null) - return; - - comp.Enabled = true; - var message = new GravityChangedEvent(gridId.Value, true); - RaiseLocalEvent(message); - - } - - public void DisableGravity(GravityComponent comp) - { - if (!comp.Enabled) - return; - - comp.Enabled = false; - Dirty(comp); - - var gridId = Transform(comp.Owner).GridUid; - if (gridId == null) - return; - - var message = new GravityChangedEvent(gridId.Value, false); - RaiseLocalEvent(message); - } - } -} diff --git a/Content.Server/Gravity/GravityGeneratorComponent.cs b/Content.Server/Gravity/GravityGeneratorComponent.cs index 64c4373c59..2ed325e52c 100644 --- a/Content.Server/Gravity/GravityGeneratorComponent.cs +++ b/Content.Server/Gravity/GravityGeneratorComponent.cs @@ -1,5 +1,4 @@ -using Content.Server.Gravity.EntitySystems; -using Content.Shared.Gravity; +using Content.Shared.Gravity; namespace Content.Server.Gravity { @@ -36,11 +35,10 @@ namespace Content.Server.Gravity /// /// Is the gravity generator currently "producing" gravity? /// - [DataField("active")] - public bool GravityActive { get; set; } = true; + [ViewVariables] + public bool GravityActive { get; set; } = false; // Do we need a UI update even if the charge doesn't change? Used by power button. [ViewVariables] public bool NeedUIUpdate { get; set; } - [ViewVariables] public bool NeedGravityUpdate { get; set; } } } diff --git a/Content.Server/Gravity/EntitySystems/GravityGeneratorSystem.cs b/Content.Server/Gravity/GravityGeneratorSystem.cs similarity index 75% rename from Content.Server/Gravity/EntitySystems/GravityGeneratorSystem.cs rename to Content.Server/Gravity/GravityGeneratorSystem.cs index aea04c0391..45899492c9 100644 --- a/Content.Server/Gravity/EntitySystems/GravityGeneratorSystem.cs +++ b/Content.Server/Gravity/GravityGeneratorSystem.cs @@ -3,23 +3,21 @@ using Content.Server.Power.Components; using Content.Shared.Gravity; using Content.Shared.Interaction; using Robust.Server.GameObjects; -using Robust.Shared.Map; -namespace Content.Server.Gravity.EntitySystems +namespace Content.Server.Gravity { public sealed class GravityGeneratorSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly AmbientSoundSystem _ambientSoundSystem = default!; - [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly GravitySystem _gravitySystem = default!; - [Dependency] private readonly GravityShakeSystem _gravityShakeSystem = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnComponentInitialized); + SubscribeLocalEvent(OnCompInit); SubscribeLocalEvent(OnComponentShutdown); SubscribeLocalEvent(OnParentChanged); // Or just anchor changed? SubscribeLocalEvent(OnInteractHand); @@ -29,17 +27,21 @@ namespace Content.Server.Gravity.EntitySystems private void OnParentChanged(EntityUid uid, GravityGeneratorComponent component, ref EntParentChangedMessage args) { - // TODO consider stations with more than one generator. if (component.GravityActive && TryComp(args.OldParent, out GravityComponent? gravity)) - _gravitySystem.DisableGravity(gravity); - - UpdateGravityActive(component, false); + { + _gravitySystem.RefreshGravity(args.OldParent.Value, gravity); + } } private void OnComponentShutdown(EntityUid uid, GravityGeneratorComponent component, ComponentShutdown args) { - component.GravityActive = false; - UpdateGravityActive(component, true); + if (component.GravityActive && + TryComp(uid, out var xform) && + TryComp(xform.ParentUid, out GravityComponent? gravity)) + { + component.GravityActive = false; + _gravitySystem.RefreshGravity(xform.ParentUid, gravity); + } } public override void Update(float frameTime) @@ -50,7 +52,7 @@ namespace Content.Server.Gravity.EntitySystems .EntityQuery()) { if (!gravGen.Intact) - return; + continue; // Calculate charge rate based on power state and such. // Negative charge rate means discharging. @@ -75,8 +77,7 @@ namespace Content.Server.Gravity.EntitySystems chargeRate = -gravGen.ChargeRate; } - var updateGravity = gravGen.NeedGravityUpdate; - var shakeGravity = false; + var active = gravGen.GravityActive; var lastCharge = gravGen.Charge; gravGen.Charge = Math.Clamp(gravGen.Charge + frameTime * chargeRate, 0, 1); if (chargeRate > 0) @@ -84,8 +85,6 @@ namespace Content.Server.Gravity.EntitySystems // Charging. if (MathHelper.CloseTo(gravGen.Charge, 1) && !gravGen.GravityActive) { - shakeGravity = true; - updateGravity = true; gravGen.GravityActive = true; } } @@ -94,8 +93,6 @@ namespace Content.Server.Gravity.EntitySystems // Discharging if (MathHelper.CloseTo(gravGen.Charge, 0) && gravGen.GravityActive) { - shakeGravity = true; - updateGravity = true; gravGen.GravityActive = false; } } @@ -110,9 +107,19 @@ namespace Content.Server.Gravity.EntitySystems if (updateUI) UpdateUI(gravGen, powerReceiver, chargeRate); - if (updateGravity) + if (active != gravGen.GravityActive && + TryComp(gravGen.Owner, out var xform) && + TryComp(xform.ParentUid, out var gravity)) { - UpdateGravityActive(gravGen, shakeGravity); + // Force it on in the faster path. + if (gravGen.GravityActive) + { + _gravitySystem.EnableGravity(xform.ParentUid, gravity); + } + else + { + _gravitySystem.RefreshGravity(xform.ParentUid, gravity); + } } } } @@ -182,11 +189,8 @@ namespace Content.Server.Gravity.EntitySystems component.NeedUIUpdate = false; } - private void OnComponentInitialized(EntityUid uid, GravityGeneratorComponent component, ComponentInit args) + private void OnCompInit(EntityUid uid, GravityGeneratorComponent component, ComponentInit args) { - // Always update gravity on init. - component.NeedGravityUpdate = true; - ApcPowerReceiverComponent? powerReceiver = null; if (!Resolve(uid, ref powerReceiver, false)) return; @@ -195,23 +199,6 @@ namespace Content.Server.Gravity.EntitySystems UpdateState(component, powerReceiver); } - private void UpdateGravityActive(GravityGeneratorComponent grav, bool shake) - { - var gridId = EntityManager.GetComponent(grav.Owner).GridUid; - if (!_mapManager.TryGetGrid(gridId, out var grid)) - return; - - var gravity = EntityManager.GetComponent(gridId.Value); - - if (grav.GravityActive) - _gravitySystem.EnableGravity(gravity); - else - _gravitySystem.DisableGravity(gravity); - - if (shake) - _gravityShakeSystem.ShakeGrid(gridId.Value, gravity); - } - private void OnInteractHand(EntityUid uid, GravityGeneratorComponent component, InteractHandEvent args) { if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor)) @@ -233,7 +220,7 @@ namespace Content.Server.Gravity.EntitySystems { var uid = grav.Owner; var appearance = EntityManager.GetComponentOrNull(uid); - appearance?.SetData(GravityGeneratorVisuals.Charge, grav.Charge); + _appearance.SetData(uid, GravityGeneratorVisuals.Charge, grav.Charge, appearance); if (EntityManager.TryGetComponent(uid, out PointLightComponent? pointLight)) { @@ -243,48 +230,48 @@ namespace Content.Server.Gravity.EntitySystems if (!grav.Intact) { - MakeBroken(grav, appearance); + MakeBroken(uid, grav, appearance); } else if (powerReceiver.PowerReceived < grav.IdlePowerUse) { - MakeUnpowered(grav, appearance); + MakeUnpowered(uid, grav, appearance); } else if (!grav.SwitchedOn) { - MakeOff(grav, appearance); + MakeOff(uid, grav, appearance); } else { - MakeOn(grav, appearance); + MakeOn(uid, grav, appearance); } } - private void MakeBroken(GravityGeneratorComponent component, AppearanceComponent? appearance) + private void MakeBroken(EntityUid uid, GravityGeneratorComponent component, AppearanceComponent? appearance) { _ambientSoundSystem.SetAmbience(component.Owner, false); - appearance?.SetData(GravityGeneratorVisuals.State, GravityGeneratorStatus.Broken); + _appearance.SetData(uid, GravityGeneratorVisuals.State, GravityGeneratorStatus.Broken); } - private void MakeUnpowered(GravityGeneratorComponent component, AppearanceComponent? appearance) + private void MakeUnpowered(EntityUid uid, GravityGeneratorComponent component, AppearanceComponent? appearance) { _ambientSoundSystem.SetAmbience(component.Owner, false); - appearance?.SetData(GravityGeneratorVisuals.State, GravityGeneratorStatus.Unpowered); + _appearance.SetData(uid, GravityGeneratorVisuals.State, GravityGeneratorStatus.Unpowered, appearance); } - private void MakeOff(GravityGeneratorComponent component, AppearanceComponent? appearance) + private void MakeOff(EntityUid uid, GravityGeneratorComponent component, AppearanceComponent? appearance) { _ambientSoundSystem.SetAmbience(component.Owner, false); - appearance?.SetData(GravityGeneratorVisuals.State, GravityGeneratorStatus.Off); + _appearance.SetData(uid, GravityGeneratorVisuals.State, GravityGeneratorStatus.Off, appearance); } - private void MakeOn(GravityGeneratorComponent component, AppearanceComponent? appearance) + private void MakeOn(EntityUid uid, GravityGeneratorComponent component, AppearanceComponent? appearance) { _ambientSoundSystem.SetAmbience(component.Owner, true); - appearance?.SetData(GravityGeneratorVisuals.State, GravityGeneratorStatus.On); + _appearance.SetData(uid, GravityGeneratorVisuals.State, GravityGeneratorStatus.On, appearance); } private void OnSwitchGenerator( diff --git a/Content.Server/Gravity/GravitySystem.cs b/Content.Server/Gravity/GravitySystem.cs new file mode 100644 index 0000000000..21083c9b47 --- /dev/null +++ b/Content.Server/Gravity/GravitySystem.cs @@ -0,0 +1,74 @@ +using Content.Shared.Gravity; +using JetBrains.Annotations; +using Robust.Shared.Map.Components; +using Robust.Shared.Utility; + +namespace Content.Server.Gravity +{ + [UsedImplicitly] + public sealed class GravitySystem : SharedGravitySystem + { + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnGravityInit); + } + + /// + /// Iterates gravity components and checks if this entity can have gravity applied. + /// + public void RefreshGravity(EntityUid uid, GravityComponent? gravity = null) + { + if (!Resolve(uid, ref gravity)) + return; + + var enabled = false; + + foreach (var (comp, xform) in EntityQuery(true)) + { + if (!comp.GravityActive || xform.ParentUid != uid) + continue; + + enabled = true; + break; + } + + if (enabled != gravity.Enabled) + { + gravity.Enabled = enabled; + var ev = new GravityChangedEvent(uid, enabled); + RaiseLocalEvent(uid, ref ev, true); + Dirty(gravity); + + if (HasComp(uid)) + { + StartGridShake(uid); + } + } + } + + private void OnGravityInit(EntityUid uid, GravityComponent component, ComponentInit args) + { + RefreshGravity(uid); + } + + public void EnableGravity(EntityUid uid, GravityComponent? gravity = null) + { + if (!Resolve(uid, ref gravity)) + return; + + if (gravity.Enabled) + return; + + gravity.Enabled = true; + var ev = new GravityChangedEvent(uid, true); + RaiseLocalEvent(uid, ref ev, true); + Dirty(gravity); + + if (HasComp(uid)) + { + StartGridShake(uid); + } + } + } +} diff --git a/Content.Server/Maps/PlanetCommand.cs b/Content.Server/Maps/PlanetCommand.cs index d94a766303..e248bd55a8 100644 --- a/Content.Server/Maps/PlanetCommand.cs +++ b/Content.Server/Maps/PlanetCommand.cs @@ -2,7 +2,6 @@ using System.Linq; using Content.Server.Administration; using Content.Server.Atmos; using Content.Server.Atmos.Components; -using Content.Server.Gravity.EntitySystems; using Content.Shared.Administration; using Content.Shared.Atmos; using Content.Shared.Gravity; diff --git a/Content.Server/Physics/Controllers/ConveyorController.cs b/Content.Server/Physics/Controllers/ConveyorController.cs index 7a8966d53a..71379f6fc7 100644 --- a/Content.Server/Physics/Controllers/ConveyorController.cs +++ b/Content.Server/Physics/Controllers/ConveyorController.cs @@ -1,5 +1,5 @@ using Content.Server.Conveyor; -using Content.Server.Gravity.EntitySystems; +using Content.Server.Gravity; using Content.Server.MachineLinking.Events; using Content.Server.MachineLinking.System; using Content.Server.Power.Components; diff --git a/Content.Shared/Gravity/GravityChangedEvent.cs b/Content.Shared/Gravity/GravityChangedEvent.cs index 4a697f6981..f9c656ce4a 100644 --- a/Content.Shared/Gravity/GravityChangedEvent.cs +++ b/Content.Shared/Gravity/GravityChangedEvent.cs @@ -1,15 +1,5 @@ namespace Content.Shared.Gravity { - public sealed class GravityChangedEvent : EntityEventArgs - { - public GravityChangedEvent(EntityUid changedGridIndex, bool newGravityState) - { - HasGravity = newGravityState; - ChangedGridIndex = changedGridIndex; - } - - public EntityUid ChangedGridIndex { get; } - - public bool HasGravity { get; } - } + [ByRefEvent] + public readonly record struct GravityChangedEvent(EntityUid ChangedGridIndex, bool HasGravity); } diff --git a/Content.Shared/Gravity/GravityComponent.cs b/Content.Shared/Gravity/GravityComponent.cs index 59ee649eac..638e629943 100644 --- a/Content.Shared/Gravity/GravityComponent.cs +++ b/Content.Shared/Gravity/GravityComponent.cs @@ -19,7 +19,8 @@ namespace Content.Shared.Gravity { if (Enabled == value) return; Enabled = value; - IoCManager.Resolve().EventBus.RaiseLocalEvent(Owner, new GravityChangedEvent(Owner, value)); + var ev = new GravityChangedEvent(Owner, value); + IoCManager.Resolve().EventBus.RaiseLocalEvent(Owner, ref ev); Dirty(); } } diff --git a/Content.Shared/Gravity/GravityShakeComponent.cs b/Content.Shared/Gravity/GravityShakeComponent.cs new file mode 100644 index 0000000000..795c155a5e --- /dev/null +++ b/Content.Shared/Gravity/GravityShakeComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Gravity; + +/// +/// Indicates this entity is shaking due to gravity changes. +/// +[RegisterComponent, NetworkedComponent] +public sealed class GravityShakeComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), DataField("shakeTimes")] + public int ShakeTimes; + + [DataField("nextShake", customTypeSerializer:typeof(TimeOffsetSerializer))] + public TimeSpan NextShake; +} diff --git a/Content.Shared/Gravity/SharedGravitySystem.Shake.cs b/Content.Shared/Gravity/SharedGravitySystem.Shake.cs new file mode 100644 index 0000000000..84be4ebdba --- /dev/null +++ b/Content.Shared/Gravity/SharedGravitySystem.Shake.cs @@ -0,0 +1,87 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Gravity; + +public abstract partial class SharedGravitySystem +{ + protected const float GravityKick = 100.0f; + protected const float ShakeCooldown = 0.2f; + + private void InitializeShake() + { + SubscribeLocalEvent(OnShakeUnpaused); + SubscribeLocalEvent(OnShakeGetState); + SubscribeLocalEvent(OnShakeHandleState); + } + + private void OnShakeUnpaused(EntityUid uid, GravityShakeComponent component, ref EntityUnpausedEvent args) + { + component.NextShake += args.PausedTime; + } + + private void UpdateShake() + { + var curTime = Timing.CurTime; + var gravityQuery = GetEntityQuery(); + + foreach (var comp in EntityQuery()) + { + if (comp.NextShake <= curTime) + { + if (comp.ShakeTimes == 0 || !gravityQuery.TryGetComponent(comp.Owner, out var gravity)) + { + RemCompDeferred(comp.Owner); + continue; + } + + ShakeGrid(comp.Owner, gravity); + comp.ShakeTimes--; + comp.NextShake += TimeSpan.FromSeconds(ShakeCooldown); + Dirty(comp); + } + } + } + + public void StartGridShake(EntityUid uid, GravityComponent? gravity = null) + { + if (!Resolve(uid, ref gravity, false)) + return; + + if (!TryComp(uid, out var shake)) + { + shake = AddComp(uid); + shake.NextShake = Timing.CurTime; + } + + shake.ShakeTimes = 10; + Dirty(shake); + } + + protected virtual void ShakeGrid(EntityUid uid, GravityComponent? comp = null) {} + + private void OnShakeHandleState(EntityUid uid, GravityShakeComponent component, ref ComponentHandleState args) + { + if (args.Current is not GravityShakeComponentState state) + return; + + component.ShakeTimes = state.ShakeTimes; + component.NextShake = state.NextShake; + } + + private void OnShakeGetState(EntityUid uid, GravityShakeComponent component, ref ComponentGetState args) + { + args.State = new GravityShakeComponentState() + { + ShakeTimes = component.ShakeTimes, + NextShake = component.NextShake, + }; + } + + [Serializable, NetSerializable] + protected sealed class GravityShakeComponentState : ComponentState + { + public int ShakeTimes; + public TimeSpan NextShake; + } +} diff --git a/Content.Shared/Gravity/SharedGravitySystem.cs b/Content.Shared/Gravity/SharedGravitySystem.cs index 300fb65913..63bea6fad5 100644 --- a/Content.Shared/Gravity/SharedGravitySystem.cs +++ b/Content.Shared/Gravity/SharedGravitySystem.cs @@ -7,11 +7,13 @@ using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Serialization; +using Robust.Shared.Timing; namespace Content.Shared.Gravity { - public abstract class SharedGravitySystem : EntitySystem + public abstract partial class SharedGravitySystem : EntitySystem { + [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly InventorySystem _inventory = default!; @@ -29,8 +31,8 @@ namespace Content.Shared.Gravity return true; // If grid / map has gravity - if ((TryComp(xform.GridUid, out var gravity) || - TryComp(xform.MapUid, out gravity)) && gravity.Enabled) + if (TryComp(xform.GridUid, out var gravity) && gravity.Enabled || + TryComp(xform.MapUid, out gravity) && gravity.Enabled) { return false; } @@ -50,11 +52,20 @@ namespace Content.Shared.Gravity public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(HandleGridInitialize); + SubscribeLocalEvent(OnGridInit); + SubscribeLocalEvent(OnAlertsSync); SubscribeLocalEvent(OnAlertsParentChange); SubscribeLocalEvent(OnGravityChange); SubscribeLocalEvent(OnGetState); SubscribeLocalEvent(OnHandleState); + + InitializeShake(); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + UpdateShake(); } private void OnHandleState(EntityUid uid, GravityComponent component, ref ComponentHandleState args) @@ -71,7 +82,7 @@ namespace Content.Shared.Gravity args.State = new GravityComponentState(component.EnabledVV); } - private void OnGravityChange(GravityChangedEvent ev) + private void OnGravityChange(ref GravityChangedEvent ev) { foreach (var (comp, xform) in EntityQuery(true)) { @@ -88,6 +99,18 @@ namespace Content.Shared.Gravity } } + private void OnAlertsSync(AlertSyncEvent ev) + { + if (IsWeightless(ev.Euid)) + { + _alerts.ShowAlert(ev.Euid, AlertType.Weightless); + } + else + { + _alerts.ClearAlert(ev.Euid, AlertType.Weightless); + } + } + private void OnAlertsParentChange(EntityUid uid, AlertsComponent component, ref EntParentChangedMessage args) { if (IsWeightless(component.Owner)) @@ -100,7 +123,7 @@ namespace Content.Shared.Gravity } } - private void HandleGridInitialize(GridInitializeEvent ev) + private void OnGridInit(GridInitializeEvent ev) { EntityManager.EnsureComponent(ev.EntityUid); } diff --git a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs index b948396447..9e2bb5da7d 100644 --- a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs +++ b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs @@ -44,7 +44,7 @@ public abstract class SharedJetpackSystem : EntitySystem args.CanMove = true; } - private void OnJetpackUserGravityChanged(GravityChangedEvent ev) + private void OnJetpackUserGravityChanged(ref GravityChangedEvent ev) { var gridUid = ev.ChangedGridIndex; var jetpackQuery = GetEntityQuery();