From bbd8d2f6f09a6d25014959c1a5acfe09426f075c Mon Sep 17 00:00:00 2001 From: BombasterDS Date: Fri, 12 Jun 2026 22:45:45 +1000 Subject: [PATCH 1/4] DestroyInteractings component and system --- .../DestroyInteractingsComponent.cs | 58 ++++++++++++++++ .../SharedDestroyInteractingsSystem.cs | 67 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 Modules/GoobStation/Content.Goobstation.Shared/Damage/Components/DestroyInteractingsComponent.cs create mode 100644 Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs diff --git a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Components/DestroyInteractingsComponent.cs b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Components/DestroyInteractingsComponent.cs new file mode 100644 index 0000000000..dc852b8057 --- /dev/null +++ b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Components/DestroyInteractingsComponent.cs @@ -0,0 +1,58 @@ +using Content.Shared.Whitelist; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Goobstation.Common.Damage; + +/// +/// Goobstation +/// Make entity destroy other entities on interaction +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class DestroyInteractingsComponent : Component +{ + #region Logic Handlers + /// + /// Whitelist entities that this entity can destroy + /// + [DataField] + public EntityWhitelist? DestroyWhitelist; + + /// + /// Marks entities that can not be destroed by this entity + /// + [DataField] + public EntityWhitelist? DestroyBlacklist; + + /// + /// Should entity count contacts as interaction + /// + [DataField] + public bool RespectContacts = false; + + /// + /// Should entity try interaction with item in hand first + /// + [DataField] + public bool RespectHandInteraction = true; + + #endregion + + #region Visuals and Sounds + /// + /// Sound that should be played on destruction coordinates + /// + [DataField] + public SoundSpecifier? DestructionSound; + + /// + /// Entity that should instead of destroyed entity + /// + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))] + public string SpawnOnDestruction = string.Empty; + + //TODO:Particles + #endregion +} \ No newline at end of file diff --git a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs new file mode 100644 index 0000000000..4725e8fc47 --- /dev/null +++ b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs @@ -0,0 +1,67 @@ +using Content.Goobstation.Common.Damage; +using Content.Shared.Destructible; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Whitelist; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Physics.Events; + +namespace Content.Goobstation.Shared.Damage; + +public sealed partial class SharedDestroyInteractinngSystem : EntitySystem +{ + [Dependency] private SharedAudioSystem _audioSystem = default!; + [Dependency] private SharedDestructibleSystem _destructibleSystem = default!; + [Dependency] private SharedHandsSystem _handsSystem = default!; + [Dependency] private EntityWhitelistSystem _whitelistSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnCollide); + } + + private bool TryDestroyEntity(EntityUid entity, Entity destructor, out EntityUid? spawned, EntityUid? user = null) + { + spawned = null; + if (!_whitelistSystem.CheckBoth(entity, destructor.Comp.DestroyBlacklist, destructor.Comp.DestroyWhitelist)) + return false; + + var position = Transform(entity).Coordinates; + if (!_destructibleSystem.DestroyEntity(entity)) + return false; + + _audioSystem.PlayPredicted(destructor.Comp.DestructionSound, destructor, user); + spawned = PredictedSpawnAtPosition(destructor.Comp.SpawnOnDestruction, position); + + return true; + } + + #region Event Handlers + private void OnInteractUsing(Entity destructor, ref InteractUsingEvent args) + { + var target = destructor.Comp.RespectHandInteraction ? args.Used : args.User; + args.Handled = TryDestroyEntity(target, destructor, out var spawned, args.User); + + if (spawned is not { } spawnedEnt) + return; + + _handsSystem.TryPickup(args.User, spawnedEnt, animate: false); + } + + private void OnInteractHand(Entity destructor, ref InteractHandEvent args) + { + args.Handled = TryDestroyEntity(args.User, destructor, out _, args.User); + } + + private void OnCollide(Entity destructor, ref StartCollideEvent args) + { + if (destructor.Comp.RespectContacts) + TryDestroyEntity(args.OtherEntity, destructor, out _); + } + + #endregion +} \ No newline at end of file From 03f0b28c32dcceb3fc634970ce9eac52d8d448ad Mon Sep 17 00:00:00 2001 From: BombasterDS Date: Fri, 12 Jun 2026 22:46:12 +1000 Subject: [PATCH 2/4] DestroyInteractings Attacked handling --- .../Damage/Systems/SharedDestroyInteractingsSystem.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs index 4725e8fc47..ae3f61d40a 100644 --- a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs +++ b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs @@ -2,14 +2,17 @@ using Content.Shared.Destructible; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; +using Content.Shared.Weapons.Melee.Events; using Content.Shared.Whitelist; using Robust.Shared.Audio.Systems; using Robust.Shared.Physics.Events; +using Robust.Shared.Timing; namespace Content.Goobstation.Shared.Damage; public sealed partial class SharedDestroyInteractinngSystem : EntitySystem { + [Dependency] private IGameTiming _timing = default!; [Dependency] private SharedAudioSystem _audioSystem = default!; [Dependency] private SharedDestructibleSystem _destructibleSystem = default!; [Dependency] private SharedHandsSystem _handsSystem = default!; @@ -22,6 +25,7 @@ public override void Initialize() SubscribeLocalEvent(OnInteractUsing); SubscribeLocalEvent(OnInteractHand); SubscribeLocalEvent(OnCollide); + SubscribeLocalEvent(OnAttacked); } private bool TryDestroyEntity(EntityUid entity, Entity destructor, out EntityUid? spawned, EntityUid? user = null) @@ -63,5 +67,10 @@ private void OnCollide(Entity destructor, ref Star TryDestroyEntity(args.OtherEntity, destructor, out _); } + private void OnAttacked(Entity destructor, ref AttackedEvent args) + { + TryDestroyEntity(args.Used, destructor, out _, user: args.User); + } + #endregion } \ No newline at end of file From cf12159d436c314d1858fc179ded579db739bd49 Mon Sep 17 00:00:00 2001 From: BombasterDS Date: Fri, 12 Jun 2026 23:07:54 +1000 Subject: [PATCH 3/4] Fix spawn on destructor null item --- .../Damage/Systems/SharedDestroyInteractingsSystem.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs index ae3f61d40a..f9271ffc4e 100644 --- a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs +++ b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs @@ -39,7 +39,9 @@ private bool TryDestroyEntity(EntityUid entity, Entity Date: Thu, 9 Jul 2026 13:03:02 +1000 Subject: [PATCH 4/4] Destroy Interactings Fixture tweaks --- .../Damage/Components/DestroyInteractingsComponent.cs | 6 ++++++ .../Damage/Systems/SharedDestroyInteractingsSystem.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Components/DestroyInteractingsComponent.cs b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Components/DestroyInteractingsComponent.cs index dc852b8057..79ecba00a9 100644 --- a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Components/DestroyInteractingsComponent.cs +++ b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Components/DestroyInteractingsComponent.cs @@ -38,6 +38,12 @@ public sealed partial class DestroyInteractingsComponent : Component [DataField] public bool RespectHandInteraction = true; + /// + /// The colliding fixture + /// + [DataField] + public string FixtureId = "bzzz"; + #endregion #region Visuals and Sounds diff --git a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs index f9271ffc4e..5cc7eb97c8 100644 --- a/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs +++ b/Modules/GoobStation/Content.Goobstation.Shared/Damage/Systems/SharedDestroyInteractingsSystem.cs @@ -65,7 +65,7 @@ private void OnInteractHand(Entity destructor, ref private void OnCollide(Entity destructor, ref StartCollideEvent args) { - if (destructor.Comp.RespectContacts) + if (destructor.Comp.RespectContacts && destructor.Comp.FixtureId == args.OurFixtureId && args.OtherFixture.Hard && args.OurFixture.Hard) TryDestroyEntity(args.OtherEntity, destructor, out _); }