use manual component state for BaseEmitSoundComponent (#35030)

* why

* cursed
This commit is contained in:
Milon
2025-03-30 15:41:11 +02:00
committed by GitHub
parent 47f8aefc25
commit 89e59b391d
13 changed files with 75 additions and 30 deletions

View File

@@ -1,4 +1,6 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Sound.Components;
@@ -8,10 +10,9 @@ namespace Content.Shared.Sound.Components;
/// </summary>
public abstract partial class BaseEmitSoundComponent : Component
{
public static readonly AudioParams DefaultParams = AudioParams.Default.WithVolume(-2f);
[AutoNetworkedField]
[ViewVariables(VVAccess.ReadWrite)]
/// <summary>
/// The <see cref="SoundSpecifier"/> to play.
/// </summary>
[DataField(required: true)]
public SoundSpecifier? Sound;
@@ -22,3 +23,15 @@ public abstract partial class BaseEmitSoundComponent : Component
[DataField]
public bool Positional;
}
/// <summary>
/// Represents the state of <see cref="BaseEmitSoundComponent"/>.
/// </summary>
/// <remarks>This is obviously very cursed, but since the BaseEmitSoundComponent is abstract, we cannot network it.
/// AutoGenerateComponentState attribute won't work here, and since everything revolves around inheritance for some fucking reason,
/// there's no better way of doing this.</remarks>
[Serializable, NetSerializable]
public struct EmitSoundComponentState(SoundSpecifier? sound) : IComponentState
{
public SoundSpecifier? Sound { get; } = sound;
}

View File

@@ -17,6 +17,6 @@ public sealed partial class EmitSoundOnActivateComponent : BaseEmitSoundComponen
/// otherwise this might enable sound spamming, as use-delays are only initiated if the interaction was
/// handled.
/// </remarks>
[DataField("handle")]
[DataField]
public bool Handle = true;
}

View File

@@ -11,13 +11,12 @@ public sealed partial class EmitSoundOnCollideComponent : BaseEmitSoundComponent
/// <summary>
/// Minimum velocity required for the sound to play.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("minVelocity")]
[DataField("minVelocity")]
public float MinimumVelocity = 3f;
/// <summary>
/// To avoid sound spam add a cooldown to it.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField("nextSound", customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
public TimeSpan NextSound;
}

View File

@@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components;
/// Simple sound emitter that emits sound on entity drop
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class EmitSoundOnDropComponent : BaseEmitSoundComponent
{
}
public sealed partial class EmitSoundOnDropComponent : BaseEmitSoundComponent;

View File

@@ -1,5 +1,4 @@
using Content.Shared.Whitelist;
using Robust.Shared.Prototypes;
using Robust.Shared.GameStates;
namespace Content.Shared.Sound.Components;
@@ -10,6 +9,9 @@ namespace Content.Shared.Sound.Components;
[RegisterComponent, NetworkedComponent]
public sealed partial class EmitSoundOnInteractUsingComponent : BaseEmitSoundComponent
{
/// <summary>
/// The <see cref="EntityWhitelist"/> for the entities that can use this item.
/// </summary>
[DataField(required: true)]
public EntityWhitelist Whitelist = new();
}

View File

@@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components;
/// Simple sound emitter that emits sound on LandEvent
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class EmitSoundOnLandComponent : BaseEmitSoundComponent
{
}
public sealed partial class EmitSoundOnLandComponent : BaseEmitSoundComponent;

View File

@@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components;
/// Simple sound emitter that emits sound on entity pickup
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class EmitSoundOnPickupComponent : BaseEmitSoundComponent
{
}
public sealed partial class EmitSoundOnPickupComponent : BaseEmitSoundComponent;

View File

@@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components;
/// Simple sound emitter that emits sound on entity spawn.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class EmitSoundOnSpawnComponent : BaseEmitSoundComponent
{
}
public sealed partial class EmitSoundOnSpawnComponent : BaseEmitSoundComponent;

View File

@@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components;
/// Simple sound emitter that emits sound on ThrowEvent
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class EmitSoundOnThrowComponent : BaseEmitSoundComponent
{
}
public sealed partial class EmitSoundOnThrowComponent : BaseEmitSoundComponent;

View File

@@ -5,7 +5,7 @@ namespace Content.Shared.Sound.Components;
/// <summary>
/// Simple sound emitter that emits sound on UseInHand
/// </summary>
[RegisterComponent]
[RegisterComponent, NetworkedComponent]
public sealed partial class EmitSoundOnUseComponent : BaseEmitSoundComponent
{
/// <summary>
@@ -17,6 +17,6 @@ public sealed partial class EmitSoundOnUseComponent : BaseEmitSoundComponent
/// otherwise this might enable sound spamming, as use-delays are only initiated if the interaction was
/// handled.
/// </remarks>
[DataField("handle")]
[DataField]
public bool Handle = true;
}

View File

@@ -1,4 +1,5 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Sound.Components;
@@ -12,7 +13,7 @@ public sealed partial class SpamEmitSoundComponent : BaseEmitSoundComponent
/// <summary>
/// The time at which the next sound will play.
/// </summary>
[DataField, AutoPausedField, AutoNetworkedField]
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField, AutoNetworkedField]
public TimeSpan NextSound;
/// <summary>

View File

@@ -5,6 +5,4 @@ namespace Content.Shared.Sound.Components;
/// on the powered state of the entity.
/// </summary>
[RegisterComponent]
public sealed partial class SpamEmitSoundRequirePowerComponent : Component
{
}
public sealed partial class SpamEmitSoundRequirePowerComponent : Component;

View File

@@ -12,6 +12,7 @@ using Content.Shared.Whitelist;
using JetBrains.Annotations;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Network;
@@ -54,6 +55,47 @@ public abstract class SharedEmitSoundSystem : EntitySystem
SubscribeLocalEvent<EmitSoundOnCollideComponent, StartCollideEvent>(OnEmitSoundOnCollide);
SubscribeLocalEvent<SoundWhileAliveComponent, MobStateChangedEvent>(OnMobState);
// We need to handle state manually here
// BaseEmitSoundComponent isn't registered so we have to subscribe to each one
// TODO: Make it use autonetworking instead of relying on inheritance
SubscribeEmitComponent<EmitSoundOnActivateComponent>();
SubscribeEmitComponent<EmitSoundOnCollideComponent>();
SubscribeEmitComponent<EmitSoundOnDropComponent>();
SubscribeEmitComponent<EmitSoundOnInteractUsingComponent>();
SubscribeEmitComponent<EmitSoundOnLandComponent>();
SubscribeEmitComponent<EmitSoundOnPickupComponent>();
SubscribeEmitComponent<EmitSoundOnSpawnComponent>();
SubscribeEmitComponent<EmitSoundOnThrowComponent>();
SubscribeEmitComponent<EmitSoundOnUIOpenComponent>();
SubscribeEmitComponent<EmitSoundOnUseComponent>();
// Helper method so it's a little less ugly
void SubscribeEmitComponent<T>() where T : BaseEmitSoundComponent
{
SubscribeLocalEvent<T, ComponentGetState>(GetBaseEmitState);
SubscribeLocalEvent<T, ComponentHandleState>(HandleBaseEmitState);
}
}
private static void GetBaseEmitState<T>(Entity<T> ent, ref ComponentGetState args) where T : BaseEmitSoundComponent
{
args.State = new EmitSoundComponentState(ent.Comp.Sound);
}
private static void HandleBaseEmitState<T>(Entity<T> ent, ref ComponentHandleState args) where T : BaseEmitSoundComponent
{
if (args.Current is not EmitSoundComponentState state)
return;
ent.Comp.Sound = state.Sound switch
{
SoundPathSpecifier pathSpec => new SoundPathSpecifier(pathSpec.Path, pathSpec.Params),
SoundCollectionSpecifier collectionSpec => collectionSpec.Collection != null
? new SoundCollectionSpecifier(collectionSpec.Collection, collectionSpec.Params)
: null,
_ => null,
};
}
private void HandleEmitSoundOnUIOpen(EntityUid uid, EmitSoundOnUIOpenComponent component, AfterActivatableUIOpenEvent args)