From 07360a4c957c42e15e4945a21feadb21d16f34f9 Mon Sep 17 00:00:00 2001 From: Kara Date: Wed, 4 Jan 2023 12:56:35 -0600 Subject: [PATCH] `EmitSound` prediction (#13282) --- Content.Client/Sound/EmitSoundSystem.cs | 8 + .../Components/EmitSoundOnTriggerComponent.cs | 1 + .../Components/EmitSoundOnUIOpenComponent.cs | 2 + .../Components/SpamEmitSoundComponent.cs | 2 + Content.Server/Sound/EmitSoundSystem.cs | 161 ++++-------------- .../Components/BaseEmitSoundComponent.cs | 2 +- .../EmitSoundOnActivateComponent.cs | 6 +- .../Components/EmitSoundOnDropComponent.cs | 6 +- .../Components/EmitSoundOnLandComponent.cs | 6 +- .../Components/EmitSoundOnPickupComponent.cs | 6 +- .../Components/EmitSoundOnSpawnComponent.cs | 6 +- .../Components}/EmitSoundOnThrowComponent.cs | 6 +- .../Components/EmitSoundOnUseComponent.cs | 4 +- Content.Shared/Sound/SharedEmitSoundSystem.cs | 111 ++++++++++++ 14 files changed, 186 insertions(+), 141 deletions(-) create mode 100644 Content.Client/Sound/EmitSoundSystem.cs rename {Content.Server => Content.Shared}/Sound/Components/BaseEmitSoundComponent.cs (92%) rename {Content.Server => Content.Shared}/Sound/Components/EmitSoundOnActivateComponent.cs (87%) rename {Content.Server => Content.Shared}/Sound/Components/EmitSoundOnDropComponent.cs (61%) rename {Content.Server => Content.Shared}/Sound/Components/EmitSoundOnLandComponent.cs (60%) rename {Content.Server => Content.Shared}/Sound/Components/EmitSoundOnPickupComponent.cs (61%) rename {Content.Server => Content.Shared}/Sound/Components/EmitSoundOnSpawnComponent.cs (59%) rename {Content.Server/Throwing => Content.Shared/Sound/Components}/EmitSoundOnThrowComponent.cs (61%) rename {Content.Server/Interaction => Content.Shared/Sound}/Components/EmitSoundOnUseComponent.cs (90%) create mode 100644 Content.Shared/Sound/SharedEmitSoundSystem.cs diff --git a/Content.Client/Sound/EmitSoundSystem.cs b/Content.Client/Sound/EmitSoundSystem.cs new file mode 100644 index 0000000000..54d31e140d --- /dev/null +++ b/Content.Client/Sound/EmitSoundSystem.cs @@ -0,0 +1,8 @@ +using Content.Shared.Sound; + +namespace Content.Client.Sound; + +public sealed class EmitSoundSystem : SharedEmitSoundSystem +{ + +} diff --git a/Content.Server/Sound/Components/EmitSoundOnTriggerComponent.cs b/Content.Server/Sound/Components/EmitSoundOnTriggerComponent.cs index 7824e51915..40b385268a 100644 --- a/Content.Server/Sound/Components/EmitSoundOnTriggerComponent.cs +++ b/Content.Server/Sound/Components/EmitSoundOnTriggerComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Explosion.EntitySystems; +using Content.Shared.Sound.Components; namespace Content.Server.Sound.Components { diff --git a/Content.Server/Sound/Components/EmitSoundOnUIOpenComponent.cs b/Content.Server/Sound/Components/EmitSoundOnUIOpenComponent.cs index 654ba96415..afde39f459 100644 --- a/Content.Server/Sound/Components/EmitSoundOnUIOpenComponent.cs +++ b/Content.Server/Sound/Components/EmitSoundOnUIOpenComponent.cs @@ -1,3 +1,5 @@ +using Content.Shared.Sound.Components; + namespace Content.Server.Sound.Components { /// diff --git a/Content.Server/Sound/Components/SpamEmitSoundComponent.cs b/Content.Server/Sound/Components/SpamEmitSoundComponent.cs index 3058a3c65c..e89b4e01d5 100644 --- a/Content.Server/Sound/Components/SpamEmitSoundComponent.cs +++ b/Content.Server/Sound/Components/SpamEmitSoundComponent.cs @@ -1,3 +1,5 @@ +using Content.Shared.Sound.Components; + namespace Content.Server.Sound.Components { /// diff --git a/Content.Server/Sound/EmitSoundSystem.cs b/Content.Server/Sound/EmitSoundSystem.cs index 539557d486..e4defb8acc 100644 --- a/Content.Server/Sound/EmitSoundSystem.cs +++ b/Content.Server/Sound/EmitSoundSystem.cs @@ -1,142 +1,53 @@ -using Content.Server.Explosion.EntitySystems; -using Content.Server.Interaction.Components; +using Content.Server.Explosion.EntitySystems; using Content.Server.Sound.Components; -using Content.Server.Throwing; using Content.Server.UserInterface; -using Content.Server.Popups; -using Content.Shared.Hands; -using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; -using Content.Shared.Item; -using Content.Shared.Maps; -using Content.Shared.Throwing; -using JetBrains.Annotations; -using Robust.Shared.Map; -using Robust.Shared.Player; +using Content.Shared.Sound; using Robust.Shared.Random; -namespace Content.Server.Sound +namespace Content.Server.Sound; + +public sealed class EmitSoundSystem : SharedEmitSoundSystem { - /// - /// Will play a sound on various events if the affected entity has a component derived from BaseEmitSoundComponent - /// - [UsedImplicitly] - public sealed class EmitSoundSystem : EntitySystem + public override void Update(float frameTime) { - [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - - /// - - public override void Update(float frameTime) + base.Update(frameTime); + foreach (var soundSpammer in EntityQuery()) { - base.Update(frameTime); - foreach (var soundSpammer in EntityQuery()) + if (!soundSpammer.Enabled) + continue; + + soundSpammer.Accumulator += frameTime; + if (soundSpammer.Accumulator < soundSpammer.RollInterval) { - if (!soundSpammer.Enabled) - continue; + continue; + } + soundSpammer.Accumulator -= soundSpammer.RollInterval; - soundSpammer.Accumulator += frameTime; - if (soundSpammer.Accumulator < soundSpammer.RollInterval) - { - continue; - } - soundSpammer.Accumulator -= soundSpammer.RollInterval; - - if (_random.Prob(soundSpammer.PlayChance)) - { - if (soundSpammer.PopUp != null) - _popupSystem.PopupEntity(Loc.GetString(soundSpammer.PopUp), soundSpammer.Owner); - TryEmitSound(soundSpammer); - } + if (Random.Prob(soundSpammer.PlayChance)) + { + if (soundSpammer.PopUp != null) + Popup.PopupEntity(Loc.GetString(soundSpammer.PopUp), soundSpammer.Owner); + TryEmitSound(soundSpammer); } } - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(HandleEmitSpawnOnInit); - SubscribeLocalEvent(HandleEmitSoundOnLand); - SubscribeLocalEvent(HandleEmitSoundOnUseInHand); - SubscribeLocalEvent(HandleEmitSoundOnThrown); - SubscribeLocalEvent(HandleEmitSoundOnActivateInWorld); - SubscribeLocalEvent(HandleEmitSoundOnTrigger); - SubscribeLocalEvent(HandleEmitSoundOnUIOpen); - SubscribeLocalEvent(HandleEmitSoundOnPickup); - SubscribeLocalEvent(HandleEmitSoundOnDrop); - } + } - private void HandleEmitSpawnOnInit(EntityUid uid, EmitSoundOnSpawnComponent component, ComponentInit args) - { - TryEmitSound(component); - } + public override void Initialize() + { + base.Initialize(); - private void HandleEmitSoundOnTrigger(EntityUid uid, EmitSoundOnTriggerComponent component, TriggerEvent args) - { - TryEmitSound(component); - args.Handled = true; - } + SubscribeLocalEvent(HandleEmitSoundOnTrigger); + SubscribeLocalEvent(HandleEmitSoundOnUIOpen); + } - private void HandleEmitSoundOnLand(EntityUid uid, BaseEmitSoundComponent component, LandEvent arg) - { - if (!TryComp(uid, out var xform) || - !_mapManager.TryGetGrid(xform.GridUid, out var grid)) return; + private void HandleEmitSoundOnUIOpen(EntityUid eUI, EmitSoundOnUIOpenComponent component, AfterActivatableUIOpenEvent args) + { + TryEmitSound(component, args.User); + } - var tile = grid.GetTileRef(xform.Coordinates); - - // Handle maps being grids (we'll still emit the sound). - if (xform.GridUid != xform.MapUid && tile.IsSpace(_tileDefMan)) - return; - - TryEmitSound(component); - } - - private void HandleEmitSoundOnUseInHand(EntityUid eUI, EmitSoundOnUseComponent component, UseInHandEvent arg) - { - // Intentionally not checking whether the interaction has already been handled. - TryEmitSound(component); - - if (component.Handle) - arg.Handled = true; - } - - private void HandleEmitSoundOnThrown(EntityUid eUI, BaseEmitSoundComponent component, ThrownEvent arg) - { - TryEmitSound(component); - } - - private void HandleEmitSoundOnActivateInWorld(EntityUid eUI, EmitSoundOnActivateComponent component, ActivateInWorldEvent arg) - { - // Intentionally not checking whether the interaction has already been handled. - TryEmitSound(component); - - if (component.Handle) - arg.Handled = true; - } - - private void HandleEmitSoundOnUIOpen(EntityUid eUI, BaseEmitSoundComponent component, AfterActivatableUIOpenEvent arg) - { - TryEmitSound(component); - } - - private void HandleEmitSoundOnPickup(EntityUid uid, EmitSoundOnPickupComponent component, GotEquippedHandEvent args) - { - TryEmitSound(component); - } - - private void HandleEmitSoundOnDrop(EntityUid uid, EmitSoundOnDropComponent component, DroppedEvent args) - { - TryEmitSound(component); - } - - private void TryEmitSound(BaseEmitSoundComponent component) - { - if (component.Sound == null) - return; - _audioSystem.PlayPvs(component.Sound, component.Owner, component.Sound.Params.AddVolume(-2f)); - } + private void HandleEmitSoundOnTrigger(EntityUid uid, EmitSoundOnTriggerComponent component, TriggerEvent args) + { + TryEmitSound(component, args.User); + args.Handled = true; } } - diff --git a/Content.Server/Sound/Components/BaseEmitSoundComponent.cs b/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs similarity index 92% rename from Content.Server/Sound/Components/BaseEmitSoundComponent.cs rename to Content.Shared/Sound/Components/BaseEmitSoundComponent.cs index 1fe5551515..27a2a67b88 100644 --- a/Content.Server/Sound/Components/BaseEmitSoundComponent.cs +++ b/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs @@ -1,6 +1,6 @@ using Robust.Shared.Audio; -namespace Content.Server.Sound.Components +namespace Content.Shared.Sound.Components { /// /// Base sound emitter which defines most of the data fields. diff --git a/Content.Server/Sound/Components/EmitSoundOnActivateComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnActivateComponent.cs similarity index 87% rename from Content.Server/Sound/Components/EmitSoundOnActivateComponent.cs rename to Content.Shared/Sound/Components/EmitSoundOnActivateComponent.cs index 8901bbf623..501195eb79 100644 --- a/Content.Server/Sound/Components/EmitSoundOnActivateComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnActivateComponent.cs @@ -1,9 +1,11 @@ -namespace Content.Server.Sound.Components +using Robust.Shared.GameStates; + +namespace Content.Shared.Sound.Components { /// /// Simple sound emitter that emits sound on ActivateInWorld /// - [RegisterComponent] + [RegisterComponent, NetworkedComponent] public sealed class EmitSoundOnActivateComponent : BaseEmitSoundComponent { /// diff --git a/Content.Server/Sound/Components/EmitSoundOnDropComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnDropComponent.cs similarity index 61% rename from Content.Server/Sound/Components/EmitSoundOnDropComponent.cs rename to Content.Shared/Sound/Components/EmitSoundOnDropComponent.cs index 6653d50693..16a8e9995d 100644 --- a/Content.Server/Sound/Components/EmitSoundOnDropComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnDropComponent.cs @@ -1,9 +1,11 @@ -namespace Content.Server.Sound.Components +using Robust.Shared.GameStates; + +namespace Content.Shared.Sound.Components { /// /// Simple sound emitter that emits sound on entity drop /// - [RegisterComponent] + [RegisterComponent, NetworkedComponent] public sealed class EmitSoundOnDropComponent : BaseEmitSoundComponent { } diff --git a/Content.Server/Sound/Components/EmitSoundOnLandComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnLandComponent.cs similarity index 60% rename from Content.Server/Sound/Components/EmitSoundOnLandComponent.cs rename to Content.Shared/Sound/Components/EmitSoundOnLandComponent.cs index 0248cbbad7..8507d2d15e 100644 --- a/Content.Server/Sound/Components/EmitSoundOnLandComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnLandComponent.cs @@ -1,9 +1,11 @@ -namespace Content.Server.Sound.Components +using Robust.Shared.GameStates; + +namespace Content.Shared.Sound.Components { /// /// Simple sound emitter that emits sound on LandEvent /// - [RegisterComponent] + [RegisterComponent, NetworkedComponent] public sealed class EmitSoundOnLandComponent : BaseEmitSoundComponent { } diff --git a/Content.Server/Sound/Components/EmitSoundOnPickupComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnPickupComponent.cs similarity index 61% rename from Content.Server/Sound/Components/EmitSoundOnPickupComponent.cs rename to Content.Shared/Sound/Components/EmitSoundOnPickupComponent.cs index 9018565d9a..5fbb920f63 100644 --- a/Content.Server/Sound/Components/EmitSoundOnPickupComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnPickupComponent.cs @@ -1,9 +1,11 @@ -namespace Content.Server.Sound.Components +using Robust.Shared.GameStates; + +namespace Content.Shared.Sound.Components { /// /// Simple sound emitter that emits sound on entity pickup /// - [RegisterComponent] + [RegisterComponent, NetworkedComponent] public sealed class EmitSoundOnPickupComponent : BaseEmitSoundComponent { } diff --git a/Content.Server/Sound/Components/EmitSoundOnSpawnComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnSpawnComponent.cs similarity index 59% rename from Content.Server/Sound/Components/EmitSoundOnSpawnComponent.cs rename to Content.Shared/Sound/Components/EmitSoundOnSpawnComponent.cs index 6535b264e6..3d7a11f6ef 100644 --- a/Content.Server/Sound/Components/EmitSoundOnSpawnComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnSpawnComponent.cs @@ -1,9 +1,11 @@ -namespace Content.Server.Sound.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Sound.Components; /// /// Simple sound emitter that emits sound on entity spawn. /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent] public sealed class EmitSoundOnSpawnComponent : BaseEmitSoundComponent { } diff --git a/Content.Server/Throwing/EmitSoundOnThrowComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnThrowComponent.cs similarity index 61% rename from Content.Server/Throwing/EmitSoundOnThrowComponent.cs rename to Content.Shared/Sound/Components/EmitSoundOnThrowComponent.cs index 22105476c0..d53d691e18 100644 --- a/Content.Server/Throwing/EmitSoundOnThrowComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnThrowComponent.cs @@ -1,11 +1,11 @@ -using Content.Server.Sound.Components; +using Robust.Shared.GameStates; -namespace Content.Server.Throwing +namespace Content.Shared.Sound.Components { /// /// Simple sound emitter that emits sound on ThrowEvent /// - [RegisterComponent] + [RegisterComponent, NetworkedComponent] public sealed class EmitSoundOnThrowComponent : BaseEmitSoundComponent { } diff --git a/Content.Server/Interaction/Components/EmitSoundOnUseComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnUseComponent.cs similarity index 90% rename from Content.Server/Interaction/Components/EmitSoundOnUseComponent.cs rename to Content.Shared/Sound/Components/EmitSoundOnUseComponent.cs index dfbe3537b2..6a7b1e120e 100644 --- a/Content.Server/Interaction/Components/EmitSoundOnUseComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnUseComponent.cs @@ -1,6 +1,6 @@ -using Content.Server.Sound.Components; +using Robust.Shared.GameStates; -namespace Content.Server.Interaction.Components +namespace Content.Shared.Sound.Components { /// /// Simple sound emitter that emits sound on UseInHand diff --git a/Content.Shared/Sound/SharedEmitSoundSystem.cs b/Content.Shared/Sound/SharedEmitSoundSystem.cs new file mode 100644 index 0000000000..b34ff65b60 --- /dev/null +++ b/Content.Shared/Sound/SharedEmitSoundSystem.cs @@ -0,0 +1,111 @@ +using Content.Shared.Hands; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Events; +using Content.Shared.Maps; +using Content.Shared.Popups; +using Content.Shared.Sound.Components; +using Content.Shared.Throwing; +using JetBrains.Annotations; +using Robust.Shared.Map; +using Robust.Shared.Network; +using Robust.Shared.Random; + +namespace Content.Shared.Sound +{ + /// + /// Will play a sound on various events if the affected entity has a component derived from BaseEmitSoundComponent + /// + [UsedImplicitly] + public abstract class SharedEmitSoundSystem : EntitySystem + { + [Dependency] private readonly INetManager _netMan = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; + [Dependency] protected readonly IRobustRandom Random = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] protected readonly SharedPopupSystem Popup = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(HandleEmitSpawnOnInit); + SubscribeLocalEvent(HandleEmitSoundOnLand); + SubscribeLocalEvent(HandleEmitSoundOnUseInHand); + SubscribeLocalEvent(HandleEmitSoundOnThrown); + SubscribeLocalEvent(HandleEmitSoundOnActivateInWorld); + SubscribeLocalEvent(HandleEmitSoundOnPickup); + SubscribeLocalEvent(HandleEmitSoundOnDrop); + } + + private void HandleEmitSpawnOnInit(EntityUid uid, EmitSoundOnSpawnComponent component, ComponentInit args) + { + TryEmitSound(component, predict: false); + } + + private void HandleEmitSoundOnLand(EntityUid uid, BaseEmitSoundComponent component, LandEvent args) + { + if (!TryComp(uid, out var xform) || + !_mapManager.TryGetGrid(xform.GridUid, out var grid)) + return; + + var tile = grid.GetTileRef(xform.Coordinates); + + // Handle maps being grids (we'll still emit the sound). + if (xform.GridUid != xform.MapUid && tile.IsSpace(_tileDefMan)) + return; + + // hand throwing not predicted sadly + TryEmitSound(component, args.User, false); + } + + private void HandleEmitSoundOnUseInHand(EntityUid eUI, EmitSoundOnUseComponent component, UseInHandEvent args) + { + // Intentionally not checking whether the interaction has already been handled. + TryEmitSound(component, args.User); + + if (component.Handle) + args.Handled = true; + } + + private void HandleEmitSoundOnThrown(EntityUid eUI, BaseEmitSoundComponent component, ThrownEvent args) + { + TryEmitSound(component, args.User, false); + } + + private void HandleEmitSoundOnActivateInWorld(EntityUid eUI, EmitSoundOnActivateComponent component, ActivateInWorldEvent args) + { + // Intentionally not checking whether the interaction has already been handled. + TryEmitSound(component, args.User); + + if (component.Handle) + args.Handled = true; + } + + private void HandleEmitSoundOnPickup(EntityUid uid, EmitSoundOnPickupComponent component, GotEquippedHandEvent args) + { + TryEmitSound(component, args.User); + } + + private void HandleEmitSoundOnDrop(EntityUid uid, EmitSoundOnDropComponent component, DroppedEvent args) + { + TryEmitSound(component, args.User); + } + + protected void TryEmitSound(BaseEmitSoundComponent component, EntityUid? user=null, bool predict=true) + { + if (component.Sound == null) + return; + + if (predict) + { + _audioSystem.PlayPredicted(component.Sound, component.Owner, user, component.Sound.Params.AddVolume(-2f)); + } + else if (_netMan.IsServer) + { + // don't predict sounds that client couldn't have played already + _audioSystem.PlayPvs(component.Sound, component.Owner, component.Sound.Params.AddVolume(-2f)); + } + } + } +} +