]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Fix actions not being usable, ordering, and containers (#19964)
authorDrSmugleaf <DrSmugleaf@users.noreply.github.com>
Sat, 9 Sep 2023 23:14:17 +0000 (16:14 -0700)
committerGitHub <noreply@github.com>
Sat, 9 Sep 2023 23:14:17 +0000 (16:14 -0700)
21 files changed:
Content.Client/Actions/ActionsSystem.cs
Content.Client/CombatMode/CombatModeSystem.cs
Content.Server/Abilities/Mime/MimePowersComponent.cs
Content.Server/Abilities/Mime/MimePowersSystem.cs
Content.Server/Dragon/DragonSystem.cs
Content.Server/Ghost/GhostSystem.cs
Content.Server/Guardian/GuardianSystem.cs
Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactComponent.cs
Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Actions.cs
Content.Server/Zombies/ZombieSystem.Transform.cs
Content.Shared/Actions/ActionsComponent.cs
Content.Shared/Actions/SharedActionsSystem.cs
Content.Shared/Bed/Sleep/SharedSleepingSystem.cs
Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs
Content.Shared/CombatMode/SharedCombatModeSystem.cs
Content.Shared/Devour/SharedDevourSystem.cs
Content.Shared/Implants/SharedSubdermalImplantSystem.cs
Content.Shared/Mech/EntitySystems/SharedMechSystem.cs
Content.Shared/Mobs/Systems/MobStateActionsSystem.cs
Content.Shared/Spider/SharedSpiderSystem.cs
Resources/Prototypes/Actions/types.yml

index 55ced8632ca71bbd316d5e60ac39a1487e899ecb..2d9b777abd767510600805d8ddf54da69809808a 100644 (file)
@@ -63,13 +63,16 @@ namespace Content.Client.Actions
 
         private void HandleComponentState(EntityUid uid, ActionsComponent component, ref ComponentHandleState args)
         {
-            if (args.Current is not ActionsComponentState)
+            if (args.Current is not ActionsComponentState state)
                 return;
 
+            component.Actions.Clear();
+            component.Actions.UnionWith(state.Actions);
+
             _actionHoldersQueue.Enqueue(uid);
         }
 
-        protected override void AddActionInternal(EntityUid actionId, IContainer container)
+        protected override void AddActionInternal(EntityUid holderId, EntityUid actionId, IContainer container, ActionsComponent holder)
         {
             // Sometimes the client receives actions from the server, before predicting that newly added components will add
             // their own shared actions. Just in case those systems ever decided to directly access action properties (e.g.,
@@ -80,7 +83,7 @@ namespace Content.Client.Actions
             }
             else
             {
-                container.Insert(actionId);
+                base.AddActionInternal(holderId, actionId, container, holder);
             }
         }
 
@@ -103,7 +106,7 @@ namespace Content.Client.Actions
                 ActionAdded?.Invoke(actionId);
         }
 
-        public override void RemoveAction(EntityUid holderId, EntityUid? actionId, ActionsComponent? comp = null, BaseActionComponent? action = null, bool dirty = true, ContainerManagerComponent? actionContainer = null)
+        public override void RemoveAction(EntityUid holderId, EntityUid? actionId, ActionsComponent? comp = null, BaseActionComponent? action = null, bool dirty = true)
         {
             if (GameTiming.ApplyingState)
                 return;
@@ -120,7 +123,7 @@ namespace Content.Client.Actions
                 return;
 
             dirty &= !action?.ClientExclusive ?? true;
-            base.RemoveAction(holderId, actionId, comp, action, dirty, actionContainer);
+            base.RemoveAction(holderId, actionId, comp, action, dirty);
 
             if (_playerManager.LocalPlayer?.ControlledEntity != holderId)
                 return;
@@ -281,7 +284,7 @@ namespace Content.Client.Actions
                 return;
 
             var removed = new List<EntityUid>();
-            var added = new List<EntityUid>();
+            var added = new List<(EntityUid Id, BaseActionComponent Comp)>();
             var query = GetEntityQuery<ActionsComponent>();
             var queue = new Queue<EntityUid>(_actionHoldersQueue);
             _actionHoldersQueue.Clear();
@@ -305,7 +308,7 @@ namespace Content.Client.Actions
                     if (data.ClientExclusive)
                         continue;
 
-                    if (!container.Contains(act))
+                    if (!holder.Actions.Contains(act))
                     {
                         holder.OldClientActions.Remove(act);
                         if (data.AutoRemove)
@@ -314,13 +317,15 @@ namespace Content.Client.Actions
                 }
 
                 // Anything that remains is a new action
-                foreach (var newAct in container.ContainedEntities)
+                foreach (var newAct in holder.Actions)
                 {
+                    if (!TryGetActionData(newAct, out var serverData))
+                        continue;
+
                     if (!holder.OldClientActions.ContainsKey(newAct))
-                        added.Add(newAct);
+                        added.Add((newAct, serverData));
 
-                    if (TryGetActionData(newAct, out var serverData))
-                        holder.OldClientActions[newAct] = new ActionMetaData(serverData.ClientExclusive, serverData.AutoRemove);
+                    holder.OldClientActions[newAct] = new ActionMetaData(serverData.ClientExclusive, serverData.AutoRemove);
                 }
 
                 if (_playerManager.LocalPlayer?.ControlledEntity != holderId)
@@ -331,9 +336,29 @@ namespace Content.Client.Actions
                     ActionRemoved?.Invoke(action);
                 }
 
+                added.Sort(static (a, b) =>
+                {
+                    if (a.Comp.Priority != b.Comp.Priority)
+                        return a.Comp.Priority - b.Comp.Priority;
+
+                    if (a.Comp.Provider != b.Comp.Provider)
+                    {
+                        if (a.Comp.Provider == null)
+                            return -1;
+
+                        if (b.Comp.Provider == null)
+                            return 1;
+
+                        // uid to int casting... it says "Do NOT use this in content". You can't tell me what to do.
+                        return (int) a.Comp.Provider - (int) b.Comp.Provider;
+                    }
+
+                    return 0;
+                });
+
                 foreach (var action in added)
                 {
-                    ActionAdded?.Invoke(action);
+                    ActionAdded?.Invoke(action.Item1);
                 }
 
                 ActionsUpdated?.Invoke();
index 00ac48a7980ec2e8b72fa662466df6e326f03d04..9fccfd173e8ea6139ff4ea1e411b807f35fa5767 100644 (file)
@@ -1,12 +1,10 @@
 using Content.Client.Hands.Systems;
-using Content.Shared.Actions;
+using Content.Shared.CCVar;
 using Content.Shared.CombatMode;
 using Content.Shared.Targeting;
-using Content.Shared.CCVar;
-using Robust.Client.Player;
-using Robust.Client.Input;
 using Robust.Client.Graphics;
-using Robust.Shared.GameStates;
+using Robust.Client.Input;
+using Robust.Client.Player;
 using Robust.Shared.Configuration;
 
 namespace Content.Client.CombatMode;
index 35393093b7f36ac4efd7beb696506b0a2921634f..fd4fc2c2af9c64195ea2c8c70bdebed4747548db 100644 (file)
@@ -20,10 +20,10 @@ namespace Content.Server.Abilities.Mime
         /// The wall prototype to use.
         /// </summary>
         [DataField("wallPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
-        public string WallPrototype = "ActionMimeInvisibleWall";
+        public string WallPrototype = "WallInvisible";
 
         [DataField("invisibleWallAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
-        public string? InvisibleWallAction;
+        public string? InvisibleWallAction = "ActionMimeInvisibleWall";
 
         [DataField("invisibleWallActionEntity")] public EntityUid? InvisibleWallActionEntity;
 
index 5a47fb1d8dc359b98858cbf9ab15544acba511c1..abc3b080fc195f0ed5d88255846a0d9fd265c20b 100644 (file)
@@ -28,7 +28,6 @@ namespace Content.Server.Abilities.Mime
         {
             base.Initialize();
             SubscribeLocalEvent<MimePowersComponent, ComponentInit>(OnComponentInit);
-            SubscribeLocalEvent<MimePowersComponent, MapInitEvent>(OnComponentMapInit);
             SubscribeLocalEvent<MimePowersComponent, InvisibleWallActionEvent>(OnInvisibleWall);
         }
 
@@ -55,10 +54,6 @@ namespace Content.Server.Abilities.Mime
         {
             EnsureComp<MutedComponent>(uid);
             _alertsSystem.ShowAlert(uid, AlertType.VowOfSilence);
-        }
-
-        private void OnComponentMapInit(EntityUid uid, MimePowersComponent component, MapInitEvent args)
-        {
             _actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid);
         }
 
index 0169e16c44528f978d3c4c844a04b136a6229c6b..f132e0041e125d3f0d3b9d70c3a68c4138521c92 100644 (file)
@@ -48,7 +48,6 @@ public sealed partial class DragonSystem : EntitySystem
         base.Initialize();
 
         SubscribeLocalEvent<DragonComponent, ComponentStartup>(OnStartup);
-        SubscribeLocalEvent<DragonComponent, MapInitEvent>(OnMapInit);
         SubscribeLocalEvent<DragonComponent, ComponentShutdown>(OnShutdown);
         SubscribeLocalEvent<DragonComponent, DragonSpawnRiftActionEvent>(OnDragonRift);
         SubscribeLocalEvent<DragonComponent, RefreshMovementSpeedModifiersEvent>(OnDragonMove);
@@ -296,10 +295,6 @@ public sealed partial class DragonSystem : EntitySystem
     private void OnStartup(EntityUid uid, DragonComponent component, ComponentStartup args)
     {
         Roar(component);
-    }
-
-    private void OnMapInit(EntityUid uid, DragonComponent component, MapInitEvent args)
-    {
         _actionsSystem.AddAction(uid, ref component.SpawnRiftActionEntity, component.SpawnRiftAction);
     }
 }
index 3b63bdfdc4f4e6b6f017f20e172f1504f727f5da..c7941fa7a5e2c448413c72d445e655488412e9d7 100644 (file)
@@ -47,7 +47,6 @@ namespace Content.Server.Ghost
 
             SubscribeLocalEvent<GhostComponent, ComponentStartup>(OnGhostStartup);
             SubscribeLocalEvent<GhostComponent, ComponentShutdown>(OnGhostShutdown);
-            SubscribeLocalEvent<GhostComponent, MapInitEvent>(OnGhostMapInit);
 
             SubscribeLocalEvent<GhostComponent, ExaminedEvent>(OnGhostExamine);
 
@@ -121,7 +120,20 @@ namespace Content.Server.Ghost
                 eye.VisibilityMask |= (uint) VisibilityFlags.Ghost;
             }
 
-            component.TimeOfDeath = _gameTiming.CurTime;
+            var time = _gameTiming.CurTime;
+            component.TimeOfDeath = time;
+
+            // TODO ghost: remove once ghosts are persistent and aren't deleted when returning to body
+            var action = _actions.AddAction(uid, ref component.ActionEntity, component.Action);
+            if (action?.UseDelay != null)
+            {
+                action.Cooldown = (time, time + action.UseDelay.Value);
+                Dirty(component.ActionEntity!.Value, action);
+            }
+
+            _actions.AddAction(uid, ref component.ToggleLightingActionEntity, component.ToggleLightingAction);
+            _actions.AddAction(uid, ref component.ToggleFoVActionEntity, component.ToggleFoVAction);
+            _actions.AddAction(uid, ref component.ToggleGhostsActionEntity, component.ToggleGhostsAction);
         }
 
         private void OnGhostShutdown(EntityUid uid, GhostComponent component, ComponentShutdown args)
@@ -147,22 +159,6 @@ namespace Content.Server.Ghost
             }
         }
 
-        private void OnGhostMapInit(EntityUid uid, GhostComponent component, MapInitEvent args)
-        {
-            // TODO ghost: remove once ghosts are persistent and aren't deleted when returning to body
-            var time = _gameTiming.CurTime;
-            var action = _actions.AddAction(uid, ref component.ActionEntity, component.Action);
-            if (action?.UseDelay != null)
-            {
-                action.Cooldown = (time, time + action.UseDelay.Value);
-                Dirty(component.ActionEntity!.Value, action);
-            }
-
-            _actions.AddAction(uid, ref component.ToggleLightingActionEntity, component.ToggleLightingAction);
-            _actions.AddAction(uid, ref component.ToggleFoVActionEntity, component.ToggleFoVAction);
-            _actions.AddAction(uid, ref component.ToggleGhostsActionEntity, component.ToggleGhostsAction);
-        }
-
         private void OnGhostExamine(EntityUid uid, GhostComponent component, ExaminedEvent args)
         {
             var timeSinceDeath = _gameTiming.RealTime.Subtract(component.TimeOfDeath);
index 323a0fc515a5d3e4b957795f57d3f1ab2c4d51ce..0cfcbe032e9407aa2d2a99c1f36021afd4e13fa8 100644 (file)
@@ -46,7 +46,6 @@ namespace Content.Server.Guardian
             SubscribeLocalEvent<GuardianComponent, PlayerDetachedEvent>(OnGuardianUnplayer);
 
             SubscribeLocalEvent<GuardianHostComponent, ComponentInit>(OnHostInit);
-            SubscribeLocalEvent<GuardianHostComponent, MapInitEvent>(OnHostMapInit);
             SubscribeLocalEvent<GuardianHostComponent, MoveEvent>(OnHostMove);
             SubscribeLocalEvent<GuardianHostComponent, MobStateChangedEvent>(OnHostStateChange);
             SubscribeLocalEvent<GuardianHostComponent, ComponentShutdown>(OnHostShutdown);
@@ -90,10 +89,6 @@ namespace Content.Server.Guardian
         private void OnHostInit(EntityUid uid, GuardianHostComponent component, ComponentInit args)
         {
             component.GuardianContainer = uid.EnsureContainer<ContainerSlot>("GuardianContainer");
-        }
-
-        private void OnHostMapInit(EntityUid uid, GuardianHostComponent component, MapInitEvent args)
-        {
             _actionSystem.AddAction(uid, ref component.ActionEntity, component.Action);
         }
 
index 500ce761cf83f11a66c4411f1b7824b75b556444..ec5af2a15c981d0e6e65116aad3d3b6e0898f055 100644 (file)
@@ -91,6 +91,8 @@ public sealed partial class ArtifactComponent : Component
             Volume = 3f
         }
     };
+
+    [DataField("activateActionEntity")] public EntityUid? ActivateActionEntity;
 }
 
 /// <summary>
index 91aaaa417a5fa32fc7689e1f0a22f9fb027615a7..6c4089a2dbd208096ddde1deeed08607fbf18f18 100644 (file)
@@ -18,21 +18,21 @@ public partial class ArtifactSystem
     /// </summary>
     public void InitializeActions()
     {
-        SubscribeLocalEvent<ArtifactComponent, MapInitEvent>(OnStartup);
+        SubscribeLocalEvent<ArtifactComponent, MapInitEvent>(OnMapInit);
         SubscribeLocalEvent<ArtifactComponent, ComponentRemove>(OnRemove);
 
         SubscribeLocalEvent<ArtifactComponent, ArtifactSelfActivateEvent>(OnSelfActivate);
     }
 
-    private void OnStartup(EntityUid uid, ArtifactComponent component, MapInitEvent args)
+    private void OnMapInit(EntityUid uid, ArtifactComponent component, MapInitEvent args)
     {
         RandomizeArtifact(uid, component);
-        _actions.AddAction(uid, Spawn(ArtifactActivateActionId), null);
+        _actions.AddAction(uid, ref component.ActivateActionEntity, ArtifactActivateActionId);
     }
 
     private void OnRemove(EntityUid uid, ArtifactComponent component, ComponentRemove args)
     {
-        _actions.RemoveAction(uid, ArtifactActivateActionId);
+        _actions.RemoveAction(uid, component.ActivateActionEntity);
     }
 
     private void OnSelfActivate(EntityUid uid, ArtifactComponent component, ArtifactSelfActivateEvent args)
index 4bfe961b7800858a2233e97eed5e8491372cfb12..5da7c6e8cd72167bce9846d9e0b80bec86a3df73 100644 (file)
@@ -105,8 +105,8 @@ namespace Content.Server.Zombies
 
             //This is needed for stupid entities that fuck up combat mode component
             //in an attempt to make an entity not attack. This is the easiest way to do it.
-            RemComp<CombatModeComponent>(target);
-            var combat = AddComp<CombatModeComponent>(target);
+            var combat = EnsureComp<CombatModeComponent>(target);
+            _combat.SetCanDisarm(target, false, combat);
             _combat.SetInCombatMode(target, true, combat);
 
             //This is the actual damage of the zombie. We assign the visual appearance
index c84484dfc0364c58bc6b7d4b71ca87ca385eb3f0..bceb08b121ff645328e07c251ee28aec77f9df5e 100644 (file)
@@ -13,15 +13,17 @@ public sealed partial class ActionsComponent : Component
     /// </summary>
     [ViewVariables] public readonly Dictionary<EntityUid, ActionMetaData> OldClientActions = new();
 
+    [ViewVariables] public readonly HashSet<EntityUid> Actions = new();
+
     public override bool SendOnlyToOwner => true;
 }
 
 [Serializable, NetSerializable]
 public sealed class ActionsComponentState : ComponentState
 {
-    public readonly List<EntityUid> Actions;
+    public readonly HashSet<EntityUid> Actions;
 
-    public ActionsComponentState(List<EntityUid> actions)
+    public ActionsComponentState(HashSet<EntityUid> actions)
     {
         Actions = actions;
     }
index 00514fcea3ab55c1124416cb08e04cba138b186f..12e5c2260a565fd64bcdc133ed1c1ca8386a03f2 100644 (file)
@@ -12,12 +12,14 @@ using Robust.Shared.GameStates;
 using Robust.Shared.Map;
 using Robust.Shared.Network;
 using Robust.Shared.Timing;
+using Robust.Shared.Utility;
 
 namespace Content.Shared.Actions;
 
 public abstract class SharedActionsSystem : EntitySystem
 {
     private const string ActionContainerId = "ActionContainer";
+    private const string ProvidedActionContainerId = "ProvidedActionContainer";
 
     [Dependency] protected readonly IGameTiming GameTiming = default!;
     [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
@@ -54,6 +56,10 @@ public abstract class SharedActionsSystem : EntitySystem
         SubscribeLocalEvent<EntityTargetActionComponent, GetActionDataEvent>(OnGetActionData);
         SubscribeLocalEvent<WorldTargetActionComponent, GetActionDataEvent>(OnGetActionData);
 
+        SubscribeLocalEvent<InstantActionComponent, EntGotRemovedFromContainerMessage>(OnEntGotRemovedFromContainer);
+        SubscribeLocalEvent<EntityTargetActionComponent, EntGotRemovedFromContainerMessage>(OnEntGotRemovedFromContainer);
+        SubscribeLocalEvent<WorldTargetActionComponent, EntGotRemovedFromContainerMessage>(OnEntGotRemovedFromContainer);
+
         SubscribeAllEvent<RequestPerformActionEvent>(OnActionRequest);
     }
 
@@ -127,6 +133,21 @@ public abstract class SharedActionsSystem : EntitySystem
         args.Action = component;
     }
 
+    private void OnEntGotRemovedFromContainer<T>(EntityUid uid, T component, EntGotRemovedFromContainerMessage args) where T : BaseActionComponent
+    {
+        if (args.Container.ID != ProvidedActionContainerId)
+            return;
+
+        if (TryComp(component.AttachedEntity, out ActionsComponent? actions))
+        {
+            actions.Actions.Remove(uid);
+            Dirty(component.AttachedEntity.Value, actions);
+
+            if (TryGetActionData(uid, out var action))
+                action.AttachedEntity = null;
+        }
+    }
+
     public BaseActionComponent? GetActionData(EntityUid? actionId)
     {
         if (actionId == null)
@@ -147,9 +168,11 @@ public abstract class SharedActionsSystem : EntitySystem
         return actionId != null && (action = GetActionData(actionId)) != null;
     }
 
-    protected Container EnsureContainer(EntityUid holderId)
+    protected Container EnsureContainer(EntityUid holderId, EntityUid? providerId)
     {
-        return _containerSystem.EnsureContainer<Container>(holderId, ActionContainerId);
+        return providerId == null
+            ? _containerSystem.EnsureContainer<Container>(holderId, ActionContainerId)
+            : _containerSystem.EnsureContainer<Container>(providerId.Value, ProvidedActionContainerId);
     }
 
     protected bool TryGetContainer(
@@ -160,6 +183,14 @@ public abstract class SharedActionsSystem : EntitySystem
         return _containerSystem.TryGetContainer(holderId, ActionContainerId, out container, containerManager);
     }
 
+    protected bool TryGetProvidedContainer(
+        EntityUid providerId,
+        [NotNullWhen(true)] out IContainer? container,
+        ContainerManagerComponent? containerManager = null)
+    {
+        return _containerSystem.TryGetContainer(providerId, ProvidedActionContainerId, out container, containerManager);
+    }
+
     public void SetCooldown(EntityUid? actionId, TimeSpan start, TimeSpan end)
     {
         if (actionId == null)
@@ -231,16 +262,12 @@ public abstract class SharedActionsSystem : EntitySystem
 
     private void OnActionsMapInit(EntityUid uid, ActionsComponent component, MapInitEvent args)
     {
-        EnsureContainer(uid);
+        EnsureContainer(uid, null);
     }
 
     private void OnActionsGetState(EntityUid uid, ActionsComponent component, ref ComponentGetState args)
     {
-        var actions = new List<EntityUid>();
-        if (TryGetContainer(uid, out var container))
-            actions.AddRange(container.ContainedEntities);
-
-        args.State = new ActionsComponentState(actions);
+        args.State = new ActionsComponentState(component.Actions);
     }
 
     private void OnActionsShutdown(EntityUid uid, ActionsComponent component, ComponentShutdown args)
@@ -270,7 +297,7 @@ public abstract class SharedActionsSystem : EntitySystem
         var name = Name(ev.Action, metaData);
 
         // Does the user actually have the requested action?
-        if (!TryGetContainer(user, out var container) || !container.Contains(ev.Action))
+        if (!component.Actions.Contains(ev.Action))
         {
             _adminLogger.Add(LogType.Action,
                 $"{ToPrettyString(user):user} attempted to perform an action that they do not have: {name}.");
@@ -538,16 +565,18 @@ public abstract class SharedActionsSystem : EntitySystem
         action.AttachedEntity = holderId;
         Dirty(actionId, action);
 
-        actionContainer ??= EnsureContainer(holderId);
-        AddActionInternal(actionId, actionContainer);
+        actionContainer ??= EnsureContainer(holderId, provider);
+        AddActionInternal(holderId, actionId, actionContainer, holder);
 
         if (dirty)
             Dirty(holderId, holder);
     }
 
-    protected virtual void AddActionInternal(EntityUid actionId, IContainer container)
+    protected virtual void AddActionInternal(EntityUid holderId, EntityUid actionId, IContainer container, ActionsComponent holder)
     {
         container.Insert(actionId);
+        holder.Actions.Add(actionId);
+        Dirty(holderId, holder);
     }
 
     /// <summary>
@@ -561,7 +590,7 @@ public abstract class SharedActionsSystem : EntitySystem
         comp ??= EnsureComp<ActionsComponent>(holderId);
 
         var allClientExclusive = true;
-        var container = EnsureContainer(holderId);
+        var container = EnsureContainer(holderId, provider);
 
         foreach (var actionId in actions)
         {
@@ -577,15 +606,12 @@ public abstract class SharedActionsSystem : EntitySystem
             Dirty(holderId, comp);
     }
 
-    public IEnumerable<(EntityUid Id, BaseActionComponent Comp)> GetActions(EntityUid holderId, IContainer? container = null)
+    public IEnumerable<(EntityUid Id, BaseActionComponent Comp)> GetActions(EntityUid holderId, ActionsComponent? actions = null)
     {
-        if (container == null &&
-            !TryGetContainer(holderId, out container))
-        {
+        if (!Resolve(holderId, ref actions, false))
             yield break;
-        }
 
-        foreach (var actionId in container.ContainedEntities)
+        foreach (var actionId in actions.Actions)
         {
             if (!TryGetActionData(actionId, out var action))
                 continue;
@@ -597,37 +623,39 @@ public abstract class SharedActionsSystem : EntitySystem
     /// <summary>
     ///     Remove any actions that were enabled by some other entity. Useful when unequiping items that grant actions.
     /// </summary>
-    public void RemoveProvidedActions(EntityUid holderId, EntityUid provider, ActionsComponent? comp = null, ContainerManagerComponent? actionContainer = null)
+    public void RemoveProvidedActions(EntityUid holderId, EntityUid provider, ActionsComponent? comp = null)
     {
-        if (!Resolve(holderId, ref comp, ref actionContainer, false))
+        if (!Resolve(holderId, ref comp, false))
             return;
 
-        if (!TryGetContainer(holderId, out var container, actionContainer))
+        if (!TryGetProvidedContainer(provider, out var container))
             return;
 
         foreach (var actionId in container.ContainedEntities.ToArray())
         {
             var action = GetActionData(actionId);
             if (action?.Provider == provider)
-                RemoveAction(holderId, actionId, comp, dirty: false, actionContainer: actionContainer);
+                RemoveAction(holderId, actionId, comp, dirty: false);
         }
 
         Dirty(holderId, comp);
     }
 
-    public virtual void RemoveAction(EntityUid holderId, EntityUid? actionId, ActionsComponent? comp = null, BaseActionComponent? action = null, bool dirty = true, ContainerManagerComponent? actionContainer = null)
+    public virtual void RemoveAction(EntityUid holderId, EntityUid? actionId, ActionsComponent? comp = null, BaseActionComponent? action = null, bool dirty = true)
     {
         if (actionId == null ||
-            !Resolve(holderId, ref comp, ref actionContainer, false) ||
-            !TryGetContainer(holderId, out var container, actionContainer) ||
-            !container.Contains(actionId.Value) ||
+            !Resolve(holderId, ref comp, false) ||
             TerminatingOrDeleted(actionId.Value))
         {
             return;
         }
 
         action ??= GetActionData(actionId);
-        container.Remove(actionId.Value);
+
+        if (TryGetContainer(holderId, out var container) && container.Contains(actionId.Value))
+            QueueDel(actionId.Value);
+
+        comp.Actions.Remove(actionId.Value);
 
         if (action != null)
         {
@@ -637,14 +665,16 @@ public abstract class SharedActionsSystem : EntitySystem
 
         if (dirty)
             Dirty(holderId, comp);
+
+        DebugTools.Assert(Transform(actionId.Value).ParentUid.IsValid());
     }
 
     /// <summary>
     ///     Removes all actions with the given prototype id.
     /// </summary>
-    public void RemoveAction(EntityUid holderId, string actionPrototypeId, ActionsComponent? holderComp = null, ContainerManagerComponent? actionContainer = null)
+    public void RemoveAction(EntityUid holderId, string actionPrototypeId, ActionsComponent? holderComp = null)
     {
-        if (!Resolve(holderId, ref holderComp, ref actionContainer, false))
+        if (!Resolve(holderId, ref holderComp, false))
             return;
 
         var actions = new List<(EntityUid Id, BaseActionComponent Comp)>();
@@ -654,9 +684,12 @@ public abstract class SharedActionsSystem : EntitySystem
                 actions.Add((id, comp));
         }
 
+        if (actions.Count == 0)
+            return;
+
         foreach (var action in actions)
         {
-            RemoveAction(holderId, action.Id, holderComp, action.Comp, actionContainer: actionContainer);
+            RemoveAction(holderId, action.Id, holderComp, action.Comp);
         }
     }
 
index d049699d9d562bcbaa2bed1a85f63c7aeed77e90..bb9c8dcf438471fa6dcfafc394083f6d9154a260 100644 (file)
@@ -2,6 +2,7 @@ using Content.Shared.Actions;
 using Content.Shared.Bed.Sleep;
 using Content.Shared.Eye.Blinding.Systems;
 using Content.Shared.Speech;
+using Robust.Shared.Network;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Timing;
 
@@ -10,6 +11,7 @@ namespace Content.Server.Bed.Sleep
     public abstract class SharedSleepingSystem : EntitySystem
     {
         [Dependency] private readonly IGameTiming _gameTiming = default!;
+        [Dependency] private readonly INetManager _net = default!;
         [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
         [Dependency] private readonly BlindableSystem _blindableSystem = default!;
 
@@ -19,7 +21,6 @@ namespace Content.Server.Bed.Sleep
         {
             base.Initialize();
             SubscribeLocalEvent<SleepingComponent, ComponentStartup>(OnStartup);
-            SubscribeLocalEvent<SleepingComponent, MapInitEvent>(OnMapInit);
             SubscribeLocalEvent<SleepingComponent, ComponentShutdown>(OnShutdown);
             SubscribeLocalEvent<SleepingComponent, SpeakAttemptEvent>(OnSpeakAttempt);
             SubscribeLocalEvent<SleepingComponent, CanSeeAttemptEvent>(OnSeeAttempt);
@@ -37,10 +38,10 @@ namespace Content.Server.Bed.Sleep
             var ev = new SleepStateChangedEvent(true);
             RaiseLocalEvent(uid, ev);
             _blindableSystem.UpdateIsBlind(uid);
-        }
 
-        private void OnMapInit(EntityUid uid, SleepingComponent component, MapInitEvent args)
-        {
+            if (_net.IsClient)
+                return;
+
             component.WakeAction = Spawn(WakeActionId);
             _actionsSystem.SetCooldown(component.WakeAction, _gameTiming.CurTime, _gameTiming.CurTime + TimeSpan.FromSeconds(15));
             _actionsSystem.AddAction(uid, component.WakeAction.Value, null);
index 06ef6728fae592d98fb60698771f377d4b242cc9..ae143e1f904ec43a48d7aeb7cc7ec52d94930e17 100644 (file)
@@ -9,7 +9,6 @@ using Content.Shared.Popups;
 using Content.Shared.Strip;
 using Content.Shared.Verbs;
 using Robust.Shared.Containers;
-using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 using Robust.Shared.Utility;
 
@@ -23,7 +22,6 @@ public sealed class ToggleableClothingSystem : EntitySystem
     [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
     [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
     [Dependency] private readonly SharedStrippableSystem _strippable = default!;
-    [Dependency] private readonly IPrototypeManager _proto = default!;
 
     private Queue<EntityUid> _toInsert = new();
 
@@ -283,8 +281,6 @@ public sealed class ToggleableClothingSystem : EntitySystem
             return;
         }
 
-        component.ActionEntity ??= Spawn(component.Action);
-
         if (component.ClothingUid != null && component.ActionEntity != null)
         {
             DebugTools.Assert(Exists(component.ClothingUid), "Toggleable clothing is missing expected entity.");
index 5b208a08f9720d5e97263b53b56f2b3a2201b992..263f3e8311abe229ae39337a368a9ebc45d60786 100644 (file)
@@ -17,12 +17,12 @@ public abstract class SharedCombatModeSystem : EntitySystem
     {
         base.Initialize();
 
-        SubscribeLocalEvent<CombatModeComponent, MapInitEvent>(OnStartup);
+        SubscribeLocalEvent<CombatModeComponent, MapInitEvent>(OnMapInit);
         SubscribeLocalEvent<CombatModeComponent, ComponentShutdown>(OnShutdown);
         SubscribeLocalEvent<CombatModeComponent, ToggleCombatActionEvent>(OnActionPerform);
     }
 
-    private void OnStartup(EntityUid uid, CombatModeComponent component, MapInitEvent args)
+    private void OnMapInit(EntityUid uid, CombatModeComponent component, MapInitEvent args)
     {
         _actionsSystem.AddAction(uid, ref component.CombatToggleActionEntity, component.CombatToggleAction);
     }
index 5ac052d3a4647eb40223b114b6c0dfb2bb8671ed..bdc198034b583631c4faf71f66c44451215b9fce 100644 (file)
@@ -21,11 +21,11 @@ public abstract class SharedDevourSystem : EntitySystem
     {
         base.Initialize();
 
-        SubscribeLocalEvent<DevourerComponent, MapInitEvent>(OnMapInit);
+        SubscribeLocalEvent<DevourerComponent, ComponentStartup>(OnStartup);
         SubscribeLocalEvent<DevourerComponent, DevourActionEvent>(OnDevourAction);
     }
 
-    protected void OnMapInit(EntityUid uid, DevourerComponent component, MapInitEvent args)
+    protected void OnStartup(EntityUid uid, DevourerComponent component, ComponentStartup args)
     {
         //Devourer doesn't actually chew, since he sends targets right into his stomach.
         //I did it mom, I added ERP content into upstream. Legally!
index 2f98093525a24e965e406ff42b5f6c0194633c8e..15780138f971a95c9c76c45c0122181ebede287d 100644 (file)
@@ -6,13 +6,13 @@ using Content.Shared.Interaction.Events;
 using Content.Shared.Mobs;
 using Content.Shared.Tag;
 using Robust.Shared.Containers;
-using Robust.Shared.Prototypes;
+using Robust.Shared.Network;
 
 namespace Content.Shared.Implants;
 
 public abstract class SharedSubdermalImplantSystem : EntitySystem
 {
-    [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+    [Dependency] private readonly INetManager _net = default!;
     [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
     [Dependency] private readonly SharedContainerSystem _container = default!;
     [Dependency] private readonly TagSystem _tag = default!;
@@ -32,7 +32,7 @@ public abstract class SharedSubdermalImplantSystem : EntitySystem
 
     private void OnInsert(EntityUid uid, SubdermalImplantComponent component, EntGotInsertedIntoContainerMessage args)
     {
-        if (component.ImplantedEntity == null)
+        if (component.ImplantedEntity == null || _net.IsClient)
             return;
 
         if (!string.IsNullOrWhiteSpace(component.ImplantAction))
index 76c3be24bb10b7b532ef9ec4764405b9bf96a279..95dd906e35010717343a885d0e3e4d19c4a676b9 100644 (file)
@@ -17,7 +17,7 @@ using Content.Shared.Popups;
 using Content.Shared.Weapons.Melee;
 using Robust.Shared.Containers;
 using Robust.Shared.GameStates;
-using Robust.Shared.Prototypes;
+using Robust.Shared.Network;
 using Robust.Shared.Serialization;
 using Robust.Shared.Timing;
 
@@ -29,7 +29,7 @@ namespace Content.Shared.Mech.EntitySystems;
 public abstract class SharedMechSystem : EntitySystem
 {
     [Dependency] private readonly IGameTiming _timing = default!;
-    [Dependency] private readonly IPrototypeManager _prototype = default!;
+    [Dependency] private readonly INetManager _net = default!;
     [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
     [Dependency] private readonly AccessReaderSystem _access = default!;
     [Dependency] private readonly SharedActionsSystem _actions = default!;
@@ -176,6 +176,9 @@ public abstract class SharedMechSystem : EntitySystem
         rider.Mech = mech;
         Dirty(pilot, rider);
 
+        if (_net.IsClient)
+            return;
+
         _actions.AddAction(pilot, Spawn(component.MechCycleAction), mech);
         _actions.AddAction(pilot, Spawn(component.MechUiAction),
             mech);
index acb1483b52693aa9766328e06b2255d80847a74c..1e5695229e58aeb5893fc6752c8357bb0b722800 100644 (file)
@@ -1,6 +1,6 @@
 using Content.Shared.Actions;
 using Content.Shared.Mobs.Components;
-using Robust.Shared.Prototypes;
+using Robust.Shared.Network;
 
 namespace Content.Shared.Mobs.Systems;
 
@@ -9,7 +9,7 @@ namespace Content.Shared.Mobs.Systems;
 /// </summary>
 public sealed class MobStateActionsSystem : EntitySystem
 {
-    [Dependency] private readonly IPrototypeManager _proto = default!;
+    [Dependency] private readonly INetManager _net = default!;
     [Dependency] private readonly SharedActionsSystem _actions = default!;
 
     /// <inheritdoc/>
@@ -20,6 +20,9 @@ public sealed class MobStateActionsSystem : EntitySystem
 
     private void OnMobStateChanged(EntityUid uid, MobStateActionsComponent component, MobStateChangedEvent args)
     {
+        if (_net.IsClient)
+            return;
+
         if (!TryComp<ActionsComponent>(uid, out var action))
             return;
 
@@ -30,10 +33,6 @@ public sealed class MobStateActionsSystem : EntitySystem
 
             foreach (var item in acts)
             {
-                if (!_proto.TryIndex<EntityPrototype>(item, out var proto))
-                    continue;
-
-                var instance = Spawn(item);
                 if (state == args.OldMobState)
                 {
                     // Don't remove actions that would be getting readded anyway
@@ -41,11 +40,11 @@ public sealed class MobStateActionsSystem : EntitySystem
                         && value.Contains(item))
                         continue;
 
-                    _actions.RemoveAction(uid, instance, action);
+                    _actions.RemoveAction(uid, item, action);
                 }
                 else if (state == args.NewMobState)
                 {
-                    _actions.AddAction(uid, instance, null, action);
+                    _actions.AddAction(uid, Spawn(item), null, action);
                 }
             }
         }
index 7871e55e57492c7782a3d620aca35b4cb05ef149..f6ee5711e74dd5d6be94a7cadb91e9978ee1b2b4 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Actions;
+using Robust.Shared.Network;
 using Robust.Shared.Random;
 
 namespace Content.Shared.Spider;
@@ -6,6 +7,7 @@ namespace Content.Shared.Spider;
 public abstract class SharedSpiderSystem : EntitySystem
 {
     [Dependency] private readonly SharedActionsSystem _action = default!;
+    [Dependency] private readonly INetManager _net = default!;
     [Dependency] private readonly IRobustRandom _robustRandom = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
 
@@ -13,12 +15,15 @@ public abstract class SharedSpiderSystem : EntitySystem
     {
         base.Initialize();
 
-        SubscribeLocalEvent<SpiderComponent, MapInitEvent>(OnSpiderMapInit);
+        SubscribeLocalEvent<SpiderComponent, ComponentStartup>(OnSpiderStartup);
         SubscribeLocalEvent<SpiderWebObjectComponent, ComponentStartup>(OnWebStartup);
     }
 
-    private void OnSpiderMapInit(EntityUid uid, SpiderComponent component, MapInitEvent args)
+    private void OnSpiderStartup(EntityUid uid, SpiderComponent component, ComponentStartup args)
     {
+        if (_net.IsClient)
+            return;
+
         _action.AddAction(uid, Spawn(component.WebAction), null);
     }
 
index 518f19f1f990f83669a45940beca88b960203a19..67c6cc619c2daeaa57988f321146090380110efb 100644 (file)
     icon: Interface/Actions/harmOff.png
     iconOn: Interface/Actions/harm.png
     event: !type:ToggleCombatActionEvent
+    priority: -100
 
 - type: entity
   id: ActionCombatModeToggleOff
   - type: InstantAction
     enabled: false
     autoPopulate: false
+    priority: -100
 
 - type: entity
   id: ActionChangeVoiceMask