EmitSound prediction (#13282)

This commit is contained in:
Kara
2023-01-04 12:56:35 -06:00
committed by GitHub
parent ba0510b62e
commit 07360a4c95
14 changed files with 186 additions and 141 deletions

View File

@@ -0,0 +1,8 @@
using Content.Shared.Sound;
namespace Content.Client.Sound;
public sealed class EmitSoundSystem : SharedEmitSoundSystem
{
}

View File

@@ -1,4 +1,5 @@
using Content.Server.Explosion.EntitySystems; using Content.Server.Explosion.EntitySystems;
using Content.Shared.Sound.Components;
namespace Content.Server.Sound.Components namespace Content.Server.Sound.Components
{ {

View File

@@ -1,3 +1,5 @@
using Content.Shared.Sound.Components;
namespace Content.Server.Sound.Components namespace Content.Server.Sound.Components
{ {
/// <summary> /// <summary>

View File

@@ -1,3 +1,5 @@
using Content.Shared.Sound.Components;
namespace Content.Server.Sound.Components namespace Content.Server.Sound.Components
{ {
/// <summary> /// <summary>

View File

@@ -1,36 +1,13 @@
using Content.Server.Explosion.EntitySystems; using Content.Server.Explosion.EntitySystems;
using Content.Server.Interaction.Components;
using Content.Server.Sound.Components; using Content.Server.Sound.Components;
using Content.Server.Throwing;
using Content.Server.UserInterface; using Content.Server.UserInterface;
using Content.Server.Popups; using Content.Shared.Sound;
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 Robust.Shared.Random; using Robust.Shared.Random;
namespace Content.Server.Sound namespace Content.Server.Sound;
{
/// <summary>
/// Will play a sound on various events if the affected entity has a component derived from BaseEmitSoundComponent
/// </summary>
[UsedImplicitly]
public sealed class EmitSoundSystem : EntitySystem
{
[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!;
/// <inheritdoc />
public sealed class EmitSoundSystem : SharedEmitSoundSystem
{
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
base.Update(frameTime); base.Update(frameTime);
@@ -46,97 +23,31 @@ namespace Content.Server.Sound
} }
soundSpammer.Accumulator -= soundSpammer.RollInterval; soundSpammer.Accumulator -= soundSpammer.RollInterval;
if (_random.Prob(soundSpammer.PlayChance)) if (Random.Prob(soundSpammer.PlayChance))
{ {
if (soundSpammer.PopUp != null) if (soundSpammer.PopUp != null)
_popupSystem.PopupEntity(Loc.GetString(soundSpammer.PopUp), soundSpammer.Owner); Popup.PopupEntity(Loc.GetString(soundSpammer.PopUp), soundSpammer.Owner);
TryEmitSound(soundSpammer); TryEmitSound(soundSpammer);
} }
} }
} }
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<EmitSoundOnSpawnComponent, ComponentInit>(HandleEmitSpawnOnInit);
SubscribeLocalEvent<EmitSoundOnLandComponent, LandEvent>(HandleEmitSoundOnLand);
SubscribeLocalEvent<EmitSoundOnUseComponent, UseInHandEvent>(HandleEmitSoundOnUseInHand);
SubscribeLocalEvent<EmitSoundOnThrowComponent, ThrownEvent>(HandleEmitSoundOnThrown);
SubscribeLocalEvent<EmitSoundOnActivateComponent, ActivateInWorldEvent>(HandleEmitSoundOnActivateInWorld);
SubscribeLocalEvent<EmitSoundOnTriggerComponent, TriggerEvent>(HandleEmitSoundOnTrigger); SubscribeLocalEvent<EmitSoundOnTriggerComponent, TriggerEvent>(HandleEmitSoundOnTrigger);
SubscribeLocalEvent<EmitSoundOnUIOpenComponent, AfterActivatableUIOpenEvent>(HandleEmitSoundOnUIOpen); SubscribeLocalEvent<EmitSoundOnUIOpenComponent, AfterActivatableUIOpenEvent>(HandleEmitSoundOnUIOpen);
SubscribeLocalEvent<EmitSoundOnPickupComponent, GotEquippedHandEvent>(HandleEmitSoundOnPickup);
SubscribeLocalEvent<EmitSoundOnDropComponent, DroppedEvent>(HandleEmitSoundOnDrop);
} }
private void HandleEmitSpawnOnInit(EntityUid uid, EmitSoundOnSpawnComponent component, ComponentInit args) private void HandleEmitSoundOnUIOpen(EntityUid eUI, EmitSoundOnUIOpenComponent component, AfterActivatableUIOpenEvent args)
{ {
TryEmitSound(component); TryEmitSound(component, args.User);
} }
private void HandleEmitSoundOnTrigger(EntityUid uid, EmitSoundOnTriggerComponent component, TriggerEvent args) private void HandleEmitSoundOnTrigger(EntityUid uid, EmitSoundOnTriggerComponent component, TriggerEvent args)
{ {
TryEmitSound(component); TryEmitSound(component, args.User);
args.Handled = true; args.Handled = true;
} }
private void HandleEmitSoundOnLand(EntityUid uid, BaseEmitSoundComponent component, LandEvent arg)
{
if (!TryComp<TransformComponent>(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;
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));
}
}
}

View File

@@ -1,6 +1,6 @@
using Robust.Shared.Audio; using Robust.Shared.Audio;
namespace Content.Server.Sound.Components namespace Content.Shared.Sound.Components
{ {
/// <summary> /// <summary>
/// Base sound emitter which defines most of the data fields. /// Base sound emitter which defines most of the data fields.

View File

@@ -1,9 +1,11 @@
namespace Content.Server.Sound.Components using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components
{ {
/// <summary> /// <summary>
/// Simple sound emitter that emits sound on ActivateInWorld /// Simple sound emitter that emits sound on ActivateInWorld
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnActivateComponent : BaseEmitSoundComponent public sealed class EmitSoundOnActivateComponent : BaseEmitSoundComponent
{ {
/// <summary> /// <summary>

View File

@@ -1,9 +1,11 @@
namespace Content.Server.Sound.Components using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components
{ {
/// <summary> /// <summary>
/// Simple sound emitter that emits sound on entity drop /// Simple sound emitter that emits sound on entity drop
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnDropComponent : BaseEmitSoundComponent public sealed class EmitSoundOnDropComponent : BaseEmitSoundComponent
{ {
} }

View File

@@ -1,9 +1,11 @@
namespace Content.Server.Sound.Components using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components
{ {
/// <summary> /// <summary>
/// Simple sound emitter that emits sound on LandEvent /// Simple sound emitter that emits sound on LandEvent
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnLandComponent : BaseEmitSoundComponent public sealed class EmitSoundOnLandComponent : BaseEmitSoundComponent
{ {
} }

View File

@@ -1,9 +1,11 @@
namespace Content.Server.Sound.Components using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components
{ {
/// <summary> /// <summary>
/// Simple sound emitter that emits sound on entity pickup /// Simple sound emitter that emits sound on entity pickup
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnPickupComponent : BaseEmitSoundComponent public sealed class EmitSoundOnPickupComponent : BaseEmitSoundComponent
{ {
} }

View File

@@ -1,9 +1,11 @@
namespace Content.Server.Sound.Components; using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components;
/// <summary> /// <summary>
/// Simple sound emitter that emits sound on entity spawn. /// Simple sound emitter that emits sound on entity spawn.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnSpawnComponent : BaseEmitSoundComponent public sealed class EmitSoundOnSpawnComponent : BaseEmitSoundComponent
{ {
} }

View File

@@ -1,11 +1,11 @@
using Content.Server.Sound.Components; using Robust.Shared.GameStates;
namespace Content.Server.Throwing namespace Content.Shared.Sound.Components
{ {
/// <summary> /// <summary>
/// Simple sound emitter that emits sound on ThrowEvent /// Simple sound emitter that emits sound on ThrowEvent
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent, NetworkedComponent]
public sealed class EmitSoundOnThrowComponent : BaseEmitSoundComponent public sealed class EmitSoundOnThrowComponent : BaseEmitSoundComponent
{ {
} }

View File

@@ -1,6 +1,6 @@
using Content.Server.Sound.Components; using Robust.Shared.GameStates;
namespace Content.Server.Interaction.Components namespace Content.Shared.Sound.Components
{ {
/// <summary> /// <summary>
/// Simple sound emitter that emits sound on UseInHand /// Simple sound emitter that emits sound on UseInHand

View File

@@ -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
{
/// <summary>
/// Will play a sound on various events if the affected entity has a component derived from BaseEmitSoundComponent
/// </summary>
[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<EmitSoundOnSpawnComponent, ComponentInit>(HandleEmitSpawnOnInit);
SubscribeLocalEvent<EmitSoundOnLandComponent, LandEvent>(HandleEmitSoundOnLand);
SubscribeLocalEvent<EmitSoundOnUseComponent, UseInHandEvent>(HandleEmitSoundOnUseInHand);
SubscribeLocalEvent<EmitSoundOnThrowComponent, ThrownEvent>(HandleEmitSoundOnThrown);
SubscribeLocalEvent<EmitSoundOnActivateComponent, ActivateInWorldEvent>(HandleEmitSoundOnActivateInWorld);
SubscribeLocalEvent<EmitSoundOnPickupComponent, GotEquippedHandEvent>(HandleEmitSoundOnPickup);
SubscribeLocalEvent<EmitSoundOnDropComponent, DroppedEvent>(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<TransformComponent>(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));
}
}
}
}