diff --git a/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs b/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs index 870d20457e..7011f72ef0 100644 --- a/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs +++ b/Content.Shared/Sound/Components/BaseEmitSoundComponent.cs @@ -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; /// public abstract partial class BaseEmitSoundComponent : Component { - public static readonly AudioParams DefaultParams = AudioParams.Default.WithVolume(-2f); - - [AutoNetworkedField] - [ViewVariables(VVAccess.ReadWrite)] + /// + /// The to play. + /// [DataField(required: true)] public SoundSpecifier? Sound; @@ -22,3 +23,15 @@ public abstract partial class BaseEmitSoundComponent : Component [DataField] public bool Positional; } + +/// +/// Represents the state of . +/// +/// 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. +[Serializable, NetSerializable] +public struct EmitSoundComponentState(SoundSpecifier? sound) : IComponentState +{ + public SoundSpecifier? Sound { get; } = sound; +} diff --git a/Content.Shared/Sound/Components/EmitSoundOnActivateComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnActivateComponent.cs index 810f132d83..d6aa42177e 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnActivateComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnActivateComponent.cs @@ -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. /// - [DataField("handle")] + [DataField] public bool Handle = true; } diff --git a/Content.Shared/Sound/Components/EmitSoundOnCollideComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnCollideComponent.cs index a2cdd63ab7..4cdea05220 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnCollideComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnCollideComponent.cs @@ -11,13 +11,12 @@ public sealed partial class EmitSoundOnCollideComponent : BaseEmitSoundComponent /// /// Minimum velocity required for the sound to play. /// - [ViewVariables(VVAccess.ReadWrite), DataField("minVelocity")] + [DataField("minVelocity")] public float MinimumVelocity = 3f; /// /// To avoid sound spam add a cooldown to it. /// - [ViewVariables(VVAccess.ReadWrite), DataField("nextSound", customTypeSerializer: typeof(TimeOffsetSerializer))] - [AutoPausedField] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField] public TimeSpan NextSound; } diff --git a/Content.Shared/Sound/Components/EmitSoundOnDropComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnDropComponent.cs index 5e04295607..64ed5e60dc 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnDropComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnDropComponent.cs @@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components; /// Simple sound emitter that emits sound on entity drop /// [RegisterComponent, NetworkedComponent] -public sealed partial class EmitSoundOnDropComponent : BaseEmitSoundComponent -{ -} +public sealed partial class EmitSoundOnDropComponent : BaseEmitSoundComponent; diff --git a/Content.Shared/Sound/Components/EmitSoundOnInteractUsingComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnInteractUsingComponent.cs index 49118d9799..d0b16fcec8 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnInteractUsingComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnInteractUsingComponent.cs @@ -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 { + /// + /// The for the entities that can use this item. + /// [DataField(required: true)] public EntityWhitelist Whitelist = new(); } diff --git a/Content.Shared/Sound/Components/EmitSoundOnLandComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnLandComponent.cs index 2d33a7f5f2..d3fceb85dd 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnLandComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnLandComponent.cs @@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components; /// Simple sound emitter that emits sound on LandEvent /// [RegisterComponent, NetworkedComponent] -public sealed partial class EmitSoundOnLandComponent : BaseEmitSoundComponent -{ -} +public sealed partial class EmitSoundOnLandComponent : BaseEmitSoundComponent; diff --git a/Content.Shared/Sound/Components/EmitSoundOnPickupComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnPickupComponent.cs index ee4b4b1688..dcf73b7ac2 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnPickupComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnPickupComponent.cs @@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components; /// Simple sound emitter that emits sound on entity pickup /// [RegisterComponent, NetworkedComponent] -public sealed partial class EmitSoundOnPickupComponent : BaseEmitSoundComponent -{ -} +public sealed partial class EmitSoundOnPickupComponent : BaseEmitSoundComponent; diff --git a/Content.Shared/Sound/Components/EmitSoundOnSpawnComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnSpawnComponent.cs index 49d40ce185..20d39b3460 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnSpawnComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnSpawnComponent.cs @@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components; /// Simple sound emitter that emits sound on entity spawn. /// [RegisterComponent, NetworkedComponent] -public sealed partial class EmitSoundOnSpawnComponent : BaseEmitSoundComponent -{ -} +public sealed partial class EmitSoundOnSpawnComponent : BaseEmitSoundComponent; diff --git a/Content.Shared/Sound/Components/EmitSoundOnThrowComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnThrowComponent.cs index 5e3650a4a3..f8c0d1181b 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnThrowComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnThrowComponent.cs @@ -6,6 +6,4 @@ namespace Content.Shared.Sound.Components; /// Simple sound emitter that emits sound on ThrowEvent /// [RegisterComponent, NetworkedComponent] -public sealed partial class EmitSoundOnThrowComponent : BaseEmitSoundComponent -{ -} +public sealed partial class EmitSoundOnThrowComponent : BaseEmitSoundComponent; diff --git a/Content.Shared/Sound/Components/EmitSoundOnUseComponent.cs b/Content.Shared/Sound/Components/EmitSoundOnUseComponent.cs index a99a01cec4..ec7a277e92 100644 --- a/Content.Shared/Sound/Components/EmitSoundOnUseComponent.cs +++ b/Content.Shared/Sound/Components/EmitSoundOnUseComponent.cs @@ -5,7 +5,7 @@ namespace Content.Shared.Sound.Components; /// /// Simple sound emitter that emits sound on UseInHand /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent] public sealed partial class EmitSoundOnUseComponent : BaseEmitSoundComponent { /// @@ -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. /// - [DataField("handle")] + [DataField] public bool Handle = true; } diff --git a/Content.Shared/Sound/Components/SpamEmitSoundComponent.cs b/Content.Shared/Sound/Components/SpamEmitSoundComponent.cs index 149728a5ba..7c1428798c 100644 --- a/Content.Shared/Sound/Components/SpamEmitSoundComponent.cs +++ b/Content.Shared/Sound/Components/SpamEmitSoundComponent.cs @@ -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 /// /// The time at which the next sound will play. /// - [DataField, AutoPausedField, AutoNetworkedField] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField, AutoNetworkedField] public TimeSpan NextSound; /// diff --git a/Content.Shared/Sound/Components/SpamEmitSoundRequirePowerComponent.cs b/Content.Shared/Sound/Components/SpamEmitSoundRequirePowerComponent.cs index b0547ea398..bf5e925e0d 100644 --- a/Content.Shared/Sound/Components/SpamEmitSoundRequirePowerComponent.cs +++ b/Content.Shared/Sound/Components/SpamEmitSoundRequirePowerComponent.cs @@ -5,6 +5,4 @@ namespace Content.Shared.Sound.Components; /// on the powered state of the entity. /// [RegisterComponent] -public sealed partial class SpamEmitSoundRequirePowerComponent : Component -{ -} +public sealed partial class SpamEmitSoundRequirePowerComponent : Component; diff --git a/Content.Shared/Sound/SharedEmitSoundSystem.cs b/Content.Shared/Sound/SharedEmitSoundSystem.cs index 67aabbb74d..58d541e363 100644 --- a/Content.Shared/Sound/SharedEmitSoundSystem.cs +++ b/Content.Shared/Sound/SharedEmitSoundSystem.cs @@ -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(OnEmitSoundOnCollide); SubscribeLocalEvent(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(); + SubscribeEmitComponent(); + SubscribeEmitComponent(); + SubscribeEmitComponent(); + SubscribeEmitComponent(); + SubscribeEmitComponent(); + SubscribeEmitComponent(); + SubscribeEmitComponent(); + SubscribeEmitComponent(); + SubscribeEmitComponent(); + + // Helper method so it's a little less ugly + void SubscribeEmitComponent() where T : BaseEmitSoundComponent + { + SubscribeLocalEvent(GetBaseEmitState); + SubscribeLocalEvent(HandleBaseEmitState); + } + } + + private static void GetBaseEmitState(Entity ent, ref ComponentGetState args) where T : BaseEmitSoundComponent + { + args.State = new EmitSoundComponentState(ent.Comp.Sound); + } + + private static void HandleBaseEmitState(Entity 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)