using Robust.Shared.Audio;
-using Robust.Shared.GameStates;
-using Robust.Shared.Serialization;
namespace Content.Shared.Sound.Components;
/// <summary>
/// The <see cref="SoundSpecifier"/> to play.
/// </summary>
- [DataField(required: true)]
+ [DataField(required: true), AutoNetworkedField]
public SoundSpecifier? Sound;
/// <summary>
/// Play the sound at the position instead of parented to the source entity.
/// Useful if the entity is deleted after.
/// </summary>
- [DataField]
+ [DataField, AutoNetworkedField]
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;
-}
/// <summary>
/// Simple sound emitter that emits sound on ActivateInWorld
/// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmitSoundOnActivateComponent : BaseEmitSoundComponent
{
/// <summary>
namespace Content.Shared.Sound.Components;
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause, AutoGenerateComponentState]
public sealed partial class EmitSoundOnCollideComponent : BaseEmitSoundComponent
{
public static readonly TimeSpan CollideCooldown = TimeSpan.FromSeconds(0.2);
/// <summary>
/// Simple sound emitter that emits sound on entity drop
/// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmitSoundOnDropComponent : BaseEmitSoundComponent;
/// <summary>
/// Whenever this item is used upon by an entity, with a tag or component within a whitelist, in the hand of a user, play a sound
/// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmitSoundOnInteractUsingComponent : BaseEmitSoundComponent
{
/// <summary>
/// <summary>
/// Simple sound emitter that emits sound on LandEvent
/// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmitSoundOnLandComponent : BaseEmitSoundComponent;
/// <summary>
/// Simple sound emitter that emits sound on entity pickup
/// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmitSoundOnPickupComponent : BaseEmitSoundComponent;
/// <summary>
/// Simple sound emitter that emits sound on entity spawn.
/// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmitSoundOnSpawnComponent : BaseEmitSoundComponent;
/// <summary>
/// Simple sound emitter that emits sound on ThrowEvent
/// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmitSoundOnThrowComponent : BaseEmitSoundComponent;
/// <summary>
/// Simple sound emitter that emits sound on AfterActivatableUIOpenEvent
/// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmitSoundOnUIOpenComponent : BaseEmitSoundComponent
{
/// <summary>
/// <summary>
/// Simple sound emitter that emits sound on UseInHand
/// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class EmitSoundOnUseComponent : BaseEmitSoundComponent
{
/// <summary>
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)
/// <summary>
/// Maximum distance to throw entities.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField("throwDistance"), AutoNetworkedField]
+ [DataField, AutoNetworkedField]
public float ThrowDistance = 15f;
- [ViewVariables(VVAccess.ReadWrite), DataField("throwForce"), AutoNetworkedField]
+ [DataField, AutoNetworkedField]
public float ThrowForce = 30f;
- /// <summary>
- /// The entity currently tethered.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField("tethered"), AutoNetworkedField]
- public override EntityUid? Tethered { get; set; }
-
- [ViewVariables(VVAccess.ReadWrite), DataField("soundLaunch")]
+ [DataField("soundLaunch")]
public SoundSpecifier? LaunchSound = new SoundPathSpecifier("/Audio/Weapons/soup.ogg")
{
Params = AudioParams.Default.WithVolume(5f),
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
public sealed partial class TetherGunComponent : BaseForceGunComponent
{
- [ViewVariables(VVAccess.ReadWrite), DataField("maxDistance"), AutoNetworkedField]
+ [DataField, AutoNetworkedField]
public float MaxDistance = 10f;
-
- /// <summary>
- /// The entity the tethered target has a joint to.
- /// </summary>
- [DataField("tetherEntity"), AutoNetworkedField]
- public override EntityUid? TetherEntity { get; set; }
-
- /// <summary>
- /// The entity currently tethered.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField("tethered"), AutoNetworkedField]
- public override EntityUid? Tethered { get; set; }
}