]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
TriggerSystem improvements (#35762)
authorslarticodefast <161409025+slarticodefast@users.noreply.github.com>
Wed, 12 Mar 2025 05:31:33 +0000 (06:31 +0100)
committerGitHub <noreply@github.com>
Wed, 12 Mar 2025 05:31:33 +0000 (22:31 -0700)
* desynchronizer real

* yaml stuff from slarti branch

* C# stuff

* oops

* fix triggers

* atomize PR

---------

Co-authored-by: Flareguy <woaj9999@outlook.com>
Content.Server/Explosion/Components/SpawnOnTriggerComponent.cs
Content.Server/Explosion/Components/TriggerOnCollideComponent.cs
Content.Server/Explosion/Components/TriggerOnUseComponent.cs [new file with mode: 0644]
Content.Server/Explosion/Components/TriggerWhitelistComponent.cs [new file with mode: 0644]
Content.Server/Explosion/EntitySystems/TriggerSystem.cs
Content.Server/Polymorph/Components/PolymorphOnTriggerComponent.cs [new file with mode: 0644]
Content.Server/Polymorph/Systems/PolymorphSystem.Collide.cs [deleted file]
Content.Server/Polymorph/Systems/PolymorphSystem.Trigger.cs [new file with mode: 0644]
Content.Server/Polymorph/Systems/PolymorphSystem.cs
Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml
Resources/Prototypes/Polymorphs/polymorph.yml

index a8b36fbd84866d29732965eadf7cfa5878101e18..c28ec7faeb87038696f4a80c87baacb52225efe7 100644 (file)
@@ -1,12 +1,24 @@
 using Content.Server.Explosion.EntitySystems;
 using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
 namespace Content.Server.Explosion.Components;
 
+/// <summary>
+///     Spawns a protoype when triggered.
+/// </summary>
 [RegisterComponent, Access(typeof(TriggerSystem))]
 public sealed partial class SpawnOnTriggerComponent : Component
 {
-    [ViewVariables(VVAccess.ReadWrite), DataField("proto", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
-    public string Proto = string.Empty;
+    /// <summary>
+    ///     The prototype to spawn.
+    /// </summary>
+    [DataField(required: true)]
+    public EntProtoId Proto = string.Empty;
+
+    /// <summary>
+    ///     Use MapCoordinates for spawning?
+    ///     Set to true if you don't want the new entity parented to the spawner.
+    /// </summary>
+    [DataField]
+    public bool mapCoords;
 }
index 950bd3e462b0f9fc5b1f4b6d8d50d3d9a5e311ef..28c2ed8c34cf165022d41d3f0c8b614c8e78123a 100644 (file)
@@ -1,15 +1,20 @@
-namespace Content.Server.Explosion.Components
+namespace Content.Server.Explosion.Components;
+
+/// <summary>
+///     Triggers when colliding with another entity.
+/// </summary>
+[RegisterComponent]
+public sealed partial class TriggerOnCollideComponent : Component
 {
-    [RegisterComponent]
-    public sealed partial class TriggerOnCollideComponent : Component
-    {
-               [DataField("fixtureID", required: true)]
-               public string FixtureID = String.Empty;
+    /// <summary>
+    ///     The fixture with which to collide.
+    /// </summary>
+    [DataField(required: true)]
+    public string FixtureID = string.Empty;
 
-        /// <summary>
-        ///     Doesn't trigger if the other colliding fixture is nonhard.
-        /// </summary>
-        [DataField("ignoreOtherNonHard")]
-        public bool IgnoreOtherNonHard = true;
-    }
+    /// <summary>
+    ///     Doesn't trigger if the other colliding fixture is nonhard.
+    /// </summary>
+    [DataField]
+    public bool IgnoreOtherNonHard = true;
 }
diff --git a/Content.Server/Explosion/Components/TriggerOnUseComponent.cs b/Content.Server/Explosion/Components/TriggerOnUseComponent.cs
new file mode 100644 (file)
index 0000000..2b44d2f
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Content.Server.Explosion.Components;
+
+/// <summary>
+/// Triggers on use in hand.
+/// </summary>
+[RegisterComponent]
+public sealed partial class TriggerOnUseComponent : Component { }
diff --git a/Content.Server/Explosion/Components/TriggerWhitelistComponent.cs b/Content.Server/Explosion/Components/TriggerWhitelistComponent.cs
new file mode 100644 (file)
index 0000000..80becf1
--- /dev/null
@@ -0,0 +1,23 @@
+using Content.Shared.Whitelist;
+
+namespace Content.Server.Explosion.Components;
+
+/// <summary>
+/// Checks if the user of a Trigger satisfies a whitelist and blacklist condition.
+/// Cancels the trigger otherwise.
+/// </summary>
+[RegisterComponent]
+public sealed partial class TriggerWhitelistComponent : Component
+{
+    /// <summary>
+    /// Whitelist for what entites can cause this trigger.
+    /// </summary>
+    [DataField]
+    public EntityWhitelist? Whitelist;
+
+    /// <summary>
+    /// Blacklist for what entites can cause this trigger.
+    /// </summary>
+    [DataField]
+    public EntityWhitelist? Blacklist;
+}
index 53f6dfacf85960cab701195019418a6f9e1ff52d..0459730c6465434d325889711d4733240b1b1229 100644 (file)
@@ -14,6 +14,7 @@ using Content.Shared.Explosion.Components;
 using Content.Shared.Explosion.Components.OnTrigger;
 using Content.Shared.Implants.Components;
 using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
 using Content.Shared.Inventory;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
@@ -23,6 +24,7 @@ using Content.Shared.Slippery;
 using Content.Shared.StepTrigger.Systems;
 using Content.Shared.Trigger;
 using Content.Shared.Weapons.Ranged.Events;
+using Content.Shared.Whitelist;
 using JetBrains.Annotations;
 using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
@@ -31,10 +33,7 @@ using Robust.Shared.Physics.Events;
 using Robust.Shared.Physics.Systems;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
-using Robust.Shared.Player;
-using Content.Shared.Coordinates;
 using Robust.Shared.Utility;
-using Robust.Shared.Timing;
 
 namespace Content.Server.Explosion.EntitySystems
 {
@@ -53,6 +52,12 @@ namespace Content.Server.Explosion.EntitySystems
         }
     }
 
+    /// <summary>
+    /// Raised before a trigger is activated.
+    /// </summary>
+    [ByRefEvent]
+    public record struct BeforeTriggerEvent(EntityUid Triggered, EntityUid? User, bool Cancelled = false);
+
     /// <summary>
     /// Raised when timer trigger becomes active.
     /// </summary>
@@ -78,6 +83,7 @@ namespace Content.Server.Explosion.EntitySystems
         [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
         [Dependency] private readonly InventorySystem _inventory = default!;
         [Dependency] private readonly ElectrocutionSystem _electrocution = default!;
+        [Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
 
         public override void Initialize()
         {
@@ -93,6 +99,7 @@ namespace Content.Server.Explosion.EntitySystems
             SubscribeLocalEvent<TriggerOnSpawnComponent, MapInitEvent>(OnSpawnTriggered);
             SubscribeLocalEvent<TriggerOnCollideComponent, StartCollideEvent>(OnTriggerCollide);
             SubscribeLocalEvent<TriggerOnActivateComponent, ActivateInWorldEvent>(OnActivate);
+            SubscribeLocalEvent<TriggerOnUseComponent, UseInHandEvent>(OnUse);
             SubscribeLocalEvent<TriggerImplantActionComponent, ActivateImplantEvent>(OnImplantTrigger);
             SubscribeLocalEvent<TriggerOnStepTriggerComponent, StepTriggeredOffEvent>(OnStepTriggered);
             SubscribeLocalEvent<TriggerOnSlipComponent, SlipEvent>(OnSlipTriggered);
@@ -109,6 +116,13 @@ namespace Content.Server.Explosion.EntitySystems
             SubscribeLocalEvent<SoundOnTriggerComponent, TriggerEvent>(OnSoundTrigger);
             SubscribeLocalEvent<ShockOnTriggerComponent, TriggerEvent>(HandleShockTrigger);
             SubscribeLocalEvent<RattleComponent, TriggerEvent>(HandleRattleTrigger);
+
+            SubscribeLocalEvent<TriggerWhitelistComponent, BeforeTriggerEvent>(HandleWhitelist);
+        }
+
+        private void HandleWhitelist(Entity<TriggerWhitelistComponent> ent, ref BeforeTriggerEvent args)
+        {
+            args.Cancelled = !_whitelist.CheckBoth(args.User, ent.Comp.Blacklist, ent.Comp.Whitelist);
         }
 
         private void OnSoundTrigger(EntityUid uid, SoundOnTriggerComponent component, TriggerEvent args)
@@ -155,16 +169,23 @@ namespace Content.Server.Explosion.EntitySystems
                 RemCompDeferred<AnchorOnTriggerComponent>(uid);
         }
 
-        private void OnSpawnTrigger(EntityUid uid, SpawnOnTriggerComponent component, TriggerEvent args)
+        private void OnSpawnTrigger(Entity<SpawnOnTriggerComponent> ent, ref TriggerEvent args)
         {
-            var xform = Transform(uid);
+            var xform = Transform(ent);
 
-            var coords = xform.Coordinates;
-
-            if (!coords.IsValid(EntityManager))
-                return;
+            if (ent.Comp.mapCoords)
+            {
+                var mapCoords = _transformSystem.GetMapCoordinates(ent, xform);
+                Spawn(ent.Comp.Proto, mapCoords);
+            }
+            else
+            {
+                var coords = xform.Coordinates;
+                if (!coords.IsValid(EntityManager))
+                    return;
+                Spawn(ent.Comp.Proto, coords);
 
-            Spawn(component.Proto, coords);
+            }
         }
 
         private void HandleExplodeTrigger(EntityUid uid, ExplodeOnTriggerComponent component, TriggerEvent args)
@@ -248,6 +269,15 @@ namespace Content.Server.Explosion.EntitySystems
             args.Handled = true;
         }
 
+        private void OnUse(Entity<TriggerOnUseComponent> ent, ref UseInHandEvent args)
+        {
+            if (args.Handled)
+                return;
+
+            Trigger(ent.Owner, args.User);
+            args.Handled = true;
+        }
+
         private void OnImplantTrigger(EntityUid uid, TriggerImplantActionComponent component, ActivateImplantEvent args)
         {
             args.Handled = Trigger(uid);
@@ -275,6 +305,11 @@ namespace Content.Server.Explosion.EntitySystems
 
         public bool Trigger(EntityUid trigger, EntityUid? user = null)
         {
+            var beforeTriggerEvent = new BeforeTriggerEvent(trigger, user);
+            RaiseLocalEvent(trigger, ref beforeTriggerEvent);
+            if (beforeTriggerEvent.Cancelled)
+                return false;
+
             var triggerEvent = new TriggerEvent(trigger, user);
             EntityManager.EventBus.RaiseLocalEvent(trigger, triggerEvent, true);
             return triggerEvent.Handled;
diff --git a/Content.Server/Polymorph/Components/PolymorphOnTriggerComponent.cs b/Content.Server/Polymorph/Components/PolymorphOnTriggerComponent.cs
new file mode 100644 (file)
index 0000000..a11b4f4
--- /dev/null
@@ -0,0 +1,18 @@
+using Content.Shared.Polymorph;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Polymorph.Components;
+
+/// <summary>
+/// Intended for use with the trigger system.
+/// Polymorphs the user of the trigger.
+/// </summary>
+[RegisterComponent]
+public sealed partial class PolymorphOnTriggerComponent : Component
+{
+    /// <summary>
+    /// Polymorph settings.
+    /// </summary>
+    [DataField(required: true)]
+    public ProtoId<PolymorphPrototype> Polymorph;
+}
diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.Collide.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.Collide.cs
deleted file mode 100644 (file)
index b29f46e..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-using Content.Server.Polymorph.Components;
-using Content.Shared.Polymorph;
-using Content.Shared.Projectiles;
-using Content.Shared.Whitelist;
-using Robust.Shared.Audio;
-using Robust.Shared.Physics.Events;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.Polymorph.Systems;
-
-public partial class PolymorphSystem
-{
-    [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
-
-    /// <summary>
-    /// Need to do this so we don't get a collection enumeration error in physics by polymorphing
-    /// an entity we're colliding with
-    /// </summary>
-    private Queue<PolymorphQueuedData> _queuedPolymorphUpdates = new();
-
-    private void InitializeCollide()
-    {
-        SubscribeLocalEvent<PolymorphOnCollideComponent, StartCollideEvent>(OnPolymorphCollide);
-    }
-
-    public void UpdateCollide()
-    {
-        while (_queuedPolymorphUpdates.TryDequeue(out var data))
-        {
-            if (Deleted(data.Ent))
-                continue;
-
-            var ent = PolymorphEntity(data.Ent, data.Polymorph);
-            if (ent != null)
-                _audio.PlayPvs(data.Sound, ent.Value);
-        }
-    }
-
-    private void OnPolymorphCollide(EntityUid uid, PolymorphOnCollideComponent component, ref StartCollideEvent args)
-    {
-        if (args.OurFixtureId != SharedProjectileSystem.ProjectileFixture)
-            return;
-
-        var other = args.OtherEntity;
-        if (_whitelistSystem.IsWhitelistFail(component.Whitelist, other) ||
-            _whitelistSystem.IsBlacklistPass(component.Blacklist, other))
-            return;
-
-        _queuedPolymorphUpdates.Enqueue(new (other, component.Sound, component.Polymorph));
-    }
-}
-
-public struct PolymorphQueuedData
-{
-    public EntityUid Ent;
-    public SoundSpecifier Sound;
-    public ProtoId<PolymorphPrototype> Polymorph;
-
-    public PolymorphQueuedData(EntityUid ent, SoundSpecifier sound, ProtoId<PolymorphPrototype> polymorph)
-    {
-        Ent = ent;
-        Sound = sound;
-        Polymorph = polymorph;
-    }
-}
diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.Trigger.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.Trigger.cs
new file mode 100644 (file)
index 0000000..452b060
--- /dev/null
@@ -0,0 +1,41 @@
+using Content.Shared.Polymorph;
+using Content.Server.Polymorph.Components;
+using Content.Server.Explosion.EntitySystems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Polymorph.Systems;
+
+public sealed partial class PolymorphSystem
+{
+    /// <summary>
+    /// Need to do this so we don't get a collection enumeration error in physics by polymorphing
+    /// an entity we're colliding with in case of TriggerOnCollide.
+    /// Also makes sure other trigger effects don't activate in nullspace after we have polymorphed.
+    /// </summary>
+    private Queue<(EntityUid Ent, ProtoId<PolymorphPrototype> Polymorph)> _queuedPolymorphUpdates = new();
+
+    private void InitializeTrigger()
+    {
+        SubscribeLocalEvent<PolymorphOnTriggerComponent, TriggerEvent>(OnTrigger);
+    }
+
+    private void OnTrigger(Entity<PolymorphOnTriggerComponent> ent, ref TriggerEvent args)
+    {
+        if (args.User == null)
+            return;
+
+        _queuedPolymorphUpdates.Enqueue((args.User.Value, ent.Comp.Polymorph));
+        args.Handled = true;
+    }
+
+    public void UpdateTrigger()
+    {
+        while (_queuedPolymorphUpdates.TryDequeue(out var data))
+        {
+            if (TerminatingOrDeleted(data.Item1))
+                continue;
+
+            PolymorphEntity(data.Item1, data.Item2);
+        }
+    }
+}
index 2c06ba3be9738f071fb81ef0005010e9355b7f28..8adab1e00db4187d3a7c794b8efeb0d196f4a7c2 100644 (file)
@@ -60,8 +60,8 @@ public sealed partial class PolymorphSystem : EntitySystem
         SubscribeLocalEvent<PolymorphedEntityComponent, BeforeFullySlicedEvent>(OnBeforeFullySliced);
         SubscribeLocalEvent<PolymorphedEntityComponent, DestructionEventArgs>(OnDestruction);
 
-        InitializeCollide();
         InitializeMap();
+        InitializeTrigger();
     }
 
     public override void Update(float frameTime)
@@ -89,7 +89,7 @@ public sealed partial class PolymorphSystem : EntitySystem
             }
         }
 
-        UpdateCollide();
+        UpdateTrigger();
     }
 
     private void OnComponentStartup(Entity<PolymorphableComponent> ent, ref ComponentStartup args)
index 4c3fd937e03fa9fe7bb2642057c9b0688cea6acd..c587787d4807d0d8e3d3c12e7b8e8e4c6cdcc9aa 100644 (file)
     damage:
       types:
         Poison: 5
+  - type: TriggerOnCollide
+    fixtureID: projectile
 
 - type: entity
   id: ProjectilePolyboltCarp
   description: Nooo, I don't wanna be fish!
   categories: [ HideSpawnMenu ]
   components:
-  - type: PolymorphOnCollide
+  - type: PolymorphOnTrigger
     polymorph: WizardForcedCarp
+  - type: TriggerWhitelist
     whitelist:
       components:
       - Body
   description: Nooo, I don't wanna be monkey!
   categories: [ HideSpawnMenu ]
   components:
-  - type: PolymorphOnCollide
+  - type: PolymorphOnTrigger
     polymorph: WizardForcedMonkey
+  - type: TriggerWhitelist
     whitelist:
       components:
       - Body
     layers:
     - state: spell
       color: brown
-  - type: PolymorphOnCollide
+  - type: PolymorphOnTrigger
     polymorph: WizardWallDoor
+  - type: TriggerWhitelist
     whitelist:
       components:
       - Airlock
   description: KnoH KnoH!
   categories: [ HideSpawnMenu ]
   components:
-  - type: PolymorphOnCollide
+  - type: PolymorphOnTrigger
     polymorph: WizardForcedCluwne
+  - type: TriggerWhitelist
     whitelist:
       components:
       - Body
   description: Nooo, I don't wanna be bread!
   categories: [ HideSpawnMenu ]
   components:
-  - type: PolymorphOnCollide
+  - type: PolymorphOnTrigger
     polymorph: BreadMorph
+  - type: TriggerWhitelist
     whitelist:
       components:
       - Body
index 745e032e7dea9852c1c520ea0f078414eaa4b48f..935b2b27f544a4d33599043559ab73d7671705bd 100644 (file)
     transferDamage: true
     revertOnCrit: false
     revertOnDeath: true
+    polymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
+    exitPolymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
 
 - type: polymorph
   id: WizardForcedSkeleton
     transferDamage: true
     revertOnCrit: false
     revertOnDeath: false
+    polymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
+    exitPolymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
 
 - type: polymorph
   id: WizardForcedMonkey
     transferDamage: true
     revertOnCrit: false
     revertOnDeath: true
+    polymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
+    exitPolymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
 
 - type: polymorph
   id: WizardWallDoor
     transferDamage: false
     revertOnCrit: false
     revertOnDeath: false
+    polymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
+    exitPolymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
 
 - type: polymorph
   id: WizardForcedCluwne
     transferHumanoidAppearance: true
     inventory: Transfer
     revertOnDeath: true
+    polymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
+    exitPolymorphSound: !type:SoundPathSpecifier
+      path: /Audio/Magic/forcewall.ogg
 
 # this is a test for transferring some visual appearance stuff
 - type: polymorph