]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Action stuff (#31305)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Sun, 25 Aug 2024 12:43:31 +0000 (22:43 +1000)
committerGitHub <noreply@github.com>
Sun, 25 Aug 2024 12:43:31 +0000 (22:43 +1000)
* Action stuff

- Cleanup some event stuff
- Avoid dirtying entity unnecessarily
- Add ActionGrant as an easy way to apply / remove actions via compregistry.

* Fix merge

Content.Client/Actions/ActionsSystem.cs
Content.Client/UserInterface/Systems/Actions/ActionUIController.cs
Content.Server/Actions/ActionOnInteractSystem.cs
Content.Server/NPC/Systems/NPCUseActionOnTargetSystem.cs
Content.Shared/Actions/ActionEvents.cs
Content.Shared/Actions/ActionGrantComponent.cs [new file with mode: 0644]
Content.Shared/Actions/ActionGrantSystem.cs [new file with mode: 0644]
Content.Shared/Actions/Events/ActionComponentChangeEvent.cs [new file with mode: 0644]
Content.Shared/Actions/ItemActionGrantComponent.cs [new file with mode: 0644]
Content.Shared/Actions/SharedActionsSystem.cs

index f05e4455880def7bf8a5d4954d34de17727178bb..26a22fa8b8df373fe9e87cd1a9413ddda9fd0164 100644 (file)
@@ -259,12 +259,6 @@ namespace Content.Client.Actions
 
             if (action.ClientExclusive)
             {
-                if (instantAction.Event != null)
-                {
-                    instantAction.Event.Performer = user;
-                    instantAction.Event.Action = actionId;
-                }
-
                 PerformAction(user, actions, actionId, instantAction, instantAction.Event, GameTiming.CurTime);
             }
             else
index d67c5cbcd63e5c310ec356e58738fae753bd5341..1dffeb8d2d449757fad866e01078098b6d16ee8d 100644 (file)
@@ -219,8 +219,6 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
             if (action.Event != null)
             {
                 action.Event.Target = coords;
-                action.Event.Performer = user;
-                action.Event.Action = actionId;
             }
 
             _actionsSystem.PerformAction(user, actionComp, actionId, action, action.Event, _timing.CurTime);
@@ -254,8 +252,6 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
             if (action.Event != null)
             {
                 action.Event.Target = entity;
-                action.Event.Performer = user;
-                action.Event.Action = actionId;
             }
 
             _actionsSystem.PerformAction(user, actionComp, actionId, action, action.Event, _timing.CurTime);
@@ -295,8 +291,6 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
             {
                 action.Event.Entity = entity;
                 action.Event.Coords = coords;
-                action.Event.Performer = user;
-                action.Event.Action = actionId;
             }
 
             _actionsSystem.PerformAction(user, actionComp, actionId, action, action.Event, _timing.CurTime);
index a1f02ed1ecbb9be95d6cb84abe259cee2b19e76d..af9b0b1ddbd512291130e72d790f0e813356414b 100644 (file)
@@ -55,12 +55,6 @@ public sealed class ActionOnInteractSystem : EntitySystem
             return;
 
         var (actId, act) = _random.Pick(options);
-        if (act.Event != null)
-        {
-            act.Event.Performer = args.User;
-            act.Event.Action = actId;
-        }
-
         _actions.PerformAction(args.User, null, actId, act, act.Event, _timing.CurTime, false);
         args.Handled = true;
     }
@@ -94,8 +88,6 @@ public sealed class ActionOnInteractSystem : EntitySystem
                 var (entActId, entAct) = _random.Pick(entOptions);
                 if (entAct.Event != null)
                 {
-                    entAct.Event.Performer = args.User;
-                    entAct.Event.Action = entActId;
                     entAct.Event.Target = args.Target.Value;
                 }
 
@@ -119,8 +111,6 @@ public sealed class ActionOnInteractSystem : EntitySystem
             var (entActId, entAct) = _random.Pick(entWorldOptions);
             if (entAct.Event != null)
             {
-                entAct.Event.Performer = args.User;
-                entAct.Event.Action = entActId;
                 entAct.Event.Entity = args.Target;
                 entAct.Event.Coords = args.ClickLocation;
             }
@@ -145,8 +135,6 @@ public sealed class ActionOnInteractSystem : EntitySystem
         var (actId, act) = _random.Pick(options);
         if (act.Event != null)
         {
-            act.Event.Performer = args.User;
-            act.Event.Action = actId;
             act.Event.Target = args.ClickLocation;
         }
 
index f6cc2d146895fca2f3b427b36aaf00b06fb5b6ef..33bc8f9074c3686be93383b36e2268166f18df74 100644 (file)
@@ -36,8 +36,6 @@ public sealed class NPCUseActionOnTargetSystem : EntitySystem
 
         if (action.Event != null)
         {
-            action.Event.Performer = user;
-            action.Event.Action = user.Comp.ActionEnt.Value;
             action.Event.Coords = Transform(target).Coordinates;
         }
 
index 4f1cd6da44aa214e54ff9135afdb0f064a55f58e..6ff86604589cbe69a1f55ecb87367daaff105e63 100644 (file)
@@ -187,5 +187,10 @@ public abstract partial class BaseActionEvent : HandledEntityEventArgs
     /// <summary>
     ///     The action the event belongs to.
     /// </summary>
-    public EntityUid Action;
+    public Entity<BaseActionComponent> Action;
+
+    /// <summary>
+    /// Should we toggle the action entity?
+    /// </summary>
+    public bool Toggle;
 }
diff --git a/Content.Shared/Actions/ActionGrantComponent.cs b/Content.Shared/Actions/ActionGrantComponent.cs
new file mode 100644 (file)
index 0000000..94c3a0b
--- /dev/null
@@ -0,0 +1,17 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Actions;
+
+/// <summary>
+/// Grants actions on MapInit and removes them on shutdown
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(ActionGrantSystem))]
+public sealed partial class ActionGrantComponent : Component
+{
+    [DataField(required: true), AutoNetworkedField, AlwaysPushInheritance]
+    public List<EntProtoId> Actions = new();
+
+    [DataField, AutoNetworkedField]
+    public List<EntityUid> ActionEntities = new();
+}
diff --git a/Content.Shared/Actions/ActionGrantSystem.cs b/Content.Shared/Actions/ActionGrantSystem.cs
new file mode 100644 (file)
index 0000000..f73ecf8
--- /dev/null
@@ -0,0 +1,48 @@
+namespace Content.Shared.Actions;
+
+/// <summary>
+/// <see cref="ActionGrantComponent"/>
+/// </summary>
+public sealed class ActionGrantSystem : EntitySystem
+{
+    [Dependency] private readonly SharedActionsSystem _actions = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<ActionGrantComponent, MapInitEvent>(OnMapInit);
+        SubscribeLocalEvent<ActionGrantComponent, ComponentShutdown>(OnShutdown);
+        SubscribeLocalEvent<ItemActionGrantComponent, GetItemActionsEvent>(OnItemGet);
+    }
+
+    private void OnItemGet(Entity<ItemActionGrantComponent> ent, ref GetItemActionsEvent args)
+    {
+        if (!TryComp(ent.Owner, out ActionGrantComponent? grant))
+            return;
+
+        foreach (var action in grant.ActionEntities)
+        {
+            args.AddAction(action);
+        }
+    }
+
+    private void OnMapInit(Entity<ActionGrantComponent> ent, ref MapInitEvent args)
+    {
+        foreach (var action in ent.Comp.Actions)
+        {
+            EntityUid? actionEnt = null;
+            _actions.AddAction(ent.Owner, ref actionEnt, action);
+
+            if (actionEnt != null)
+                ent.Comp.ActionEntities.Add(actionEnt.Value);
+        }
+    }
+
+    private void OnShutdown(Entity<ActionGrantComponent> ent, ref ComponentShutdown args)
+    {
+        foreach (var actionEnt in ent.Comp.ActionEntities)
+        {
+            _actions.RemoveAction(ent.Owner, actionEnt);
+        }
+    }
+}
diff --git a/Content.Shared/Actions/Events/ActionComponentChangeEvent.cs b/Content.Shared/Actions/Events/ActionComponentChangeEvent.cs
new file mode 100644 (file)
index 0000000..c9c4db1
--- /dev/null
@@ -0,0 +1,27 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Actions.Events;
+
+/// <summary>
+/// Adds / removes the component upon action.
+/// </summary>
+[Virtual]
+public partial class ActionComponentChangeEvent : InstantActionEvent
+{
+    [DataField(required: true)]
+    public ComponentRegistry Components = new();
+}
+
+/// <summary>
+/// Similar to <see cref="ActionComponentChangeEvent"/> except raises an event to attempt to relay it.
+/// </summary>
+public sealed partial class RelayedActionComponentChangeEvent : ActionComponentChangeEvent
+{
+
+}
+
+[ByRefEvent]
+public record struct AttemptRelayActionComponentChangeEvent
+{
+    public EntityUid? Target;
+}
diff --git a/Content.Shared/Actions/ItemActionGrantComponent.cs b/Content.Shared/Actions/ItemActionGrantComponent.cs
new file mode 100644 (file)
index 0000000..d1769b5
--- /dev/null
@@ -0,0 +1,14 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Actions;
+
+/// <summary>
+/// Works in tandem with <see cref="ActionGrantComponent"/> by granting those actions to the equipper entity.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(ActionGrantSystem))]
+public sealed partial class ItemActionGrantComponent : Component
+{
+    [DataField(required: true), AutoNetworkedField, AlwaysPushInheritance]
+    public List<EntProtoId> Actions = new();
+}
index fb9415096fbfa0b2ba8ea547a9beab4f173937c0..275634542825d15474620bdaa70257caf69d2697 100644 (file)
@@ -11,7 +11,6 @@ using Content.Shared.Mind;
 using Content.Shared.Rejuvenate;
 using Content.Shared.Whitelist;
 using Robust.Shared.Audio.Systems;
-using Robust.Shared.Containers;
 using Robust.Shared.GameStates;
 using Robust.Shared.Map;
 using Robust.Shared.Timing;
@@ -45,6 +44,8 @@ public abstract class SharedActionsSystem : EntitySystem
         SubscribeLocalEvent<WorldTargetActionComponent, ComponentShutdown>(OnActionShutdown);
         SubscribeLocalEvent<EntityWorldTargetActionComponent, ComponentShutdown>(OnActionShutdown);
 
+        SubscribeLocalEvent<ActionsComponent, ActionComponentChangeEvent>(OnActionCompChange);
+        SubscribeLocalEvent<ActionsComponent, RelayedActionComponentChangeEvent>(OnRelayActionCompChange);
         SubscribeLocalEvent<ActionsComponent, DidEquipEvent>(OnDidEquip);
         SubscribeLocalEvent<ActionsComponent, DidEquipHandEvent>(OnHandEquipped);
         SubscribeLocalEvent<ActionsComponent, DidUnequipEvent>(OnDidUnequip);
@@ -490,12 +491,6 @@ public abstract class SharedActionsSystem : EntitySystem
                 break;
         }
 
-        if (performEvent != null)
-        {
-            performEvent.Performer = user;
-            performEvent.Action = actionEnt;
-        }
-
         // All checks passed. Perform the action!
         PerformAction(user, component, actionEnt, action, performEvent, curTime);
     }
@@ -641,6 +636,8 @@ public abstract class SharedActionsSystem : EntitySystem
             // This here is required because of client-side prediction (RaisePredictiveEvent results in event re-use).
             actionEvent.Handled = false;
             var target = performer;
+            actionEvent.Performer = performer;
+            actionEvent.Action = (actionId, action);
 
             if (!action.RaiseOnUser && action.Container != null && !HasComp<MindComponent>(action.Container))
                 target = action.Container.Value;
@@ -653,10 +650,14 @@ public abstract class SharedActionsSystem : EntitySystem
             return; // no interaction occurred.
 
         // play sound, reduce charges, start cooldown, and mark as dirty (if required).
+        if (actionEvent?.Toggle == true)
+        {
+            action.Toggled = !action.Toggled;
+        }
 
-        _audio.PlayPredicted(action.Sound, performer,predicted ? performer : null);
+        _audio.PlayPredicted(action.Sound, performer, predicted ? performer : null);
 
-        var dirty = toggledBefore == action.Toggled;
+        var dirty = toggledBefore != action.Toggled;
 
         if (action.Charges != null)
         {
@@ -673,10 +674,11 @@ public abstract class SharedActionsSystem : EntitySystem
             action.Cooldown = (curTime, curTime + action.UseDelay.Value);
         }
 
-        Dirty(actionId, action);
-
-        if (dirty && component != null)
-            Dirty(performer, component);
+        if (dirty)
+        {
+            Dirty(actionId, action);
+            UpdateAction(actionId, action);
+        }
 
         var ev = new ActionPerformedEvent(performer);
         RaiseLocalEvent(actionId, ref ev);
@@ -975,6 +977,47 @@ public abstract class SharedActionsSystem : EntitySystem
 
     #endregion
 
+    private void OnRelayActionCompChange(Entity<ActionsComponent> ent, ref RelayedActionComponentChangeEvent args)
+    {
+        if (args.Handled)
+            return;
+
+        var ev = new AttemptRelayActionComponentChangeEvent();
+        RaiseLocalEvent(ent.Owner, ref ev);
+        var target = ev.Target ?? ent.Owner;
+
+        args.Handled = true;
+        args.Toggle = true;
+
+        if (!args.Action.Comp.Toggled)
+        {
+            EntityManager.AddComponents(target, args.Components);
+        }
+        else
+        {
+            EntityManager.RemoveComponents(target, args.Components);
+        }
+    }
+
+    private void OnActionCompChange(Entity<ActionsComponent> ent, ref ActionComponentChangeEvent args)
+    {
+        if (args.Handled)
+            return;
+
+        args.Handled = true;
+        args.Toggle = true;
+        var target = ent.Owner;
+
+        if (!args.Action.Comp.Toggled)
+        {
+            EntityManager.AddComponents(target, args.Components);
+        }
+        else
+        {
+            EntityManager.RemoveComponents(target, args.Components);
+        }
+    }
+
     #region EquipHandlers
     private void OnDidEquip(EntityUid uid, ActionsComponent component, DidEquipEvent args)
     {