From 0b1e8a4bbc091ca07a11b3586808635a47b06445 Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Tue, 30 Dec 2025 13:41:57 -0800 Subject: [PATCH] Status Effects Toolshed (#41670) * toolshed :) * Yeah they call me the gamer * Fix test fails * refactor: extract method ZeroAsNull --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> Co-authored-by: pa.pecherskij --- .../StatusEffects/StatusEffectCommand.cs | 141 ++++++++++++++++++ .../StatusEffectCompletionParser.cs | 16 ++ .../StatusEffectNew/StatusEffectsSystem.cs | 26 ++++ .../en-US/commands/toolshed-commands.ftl | 12 +- 4 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 Content.Server/Toolshed/Commands/StatusEffects/StatusEffectCommand.cs create mode 100644 Content.Server/Toolshed/TypeParsers/StatusEffects/StatusEffectCompletionParser.cs diff --git a/Content.Server/Toolshed/Commands/StatusEffects/StatusEffectCommand.cs b/Content.Server/Toolshed/Commands/StatusEffects/StatusEffectCommand.cs new file mode 100644 index 0000000000..4182bac081 --- /dev/null +++ b/Content.Server/Toolshed/Commands/StatusEffects/StatusEffectCommand.cs @@ -0,0 +1,141 @@ +using Content.Server.Administration; +using Content.Server.Toolshed.TypeParsers.StatusEffects; +using Content.Shared.Administration; +using Content.Shared.StatusEffectNew; +using Robust.Shared.Prototypes; +using Robust.Shared.Toolshed; + +namespace Content.Server.Toolshed.Commands.StatusEffects; + +[ToolshedCommand, AdminCommand(AdminFlags.VarEdit)] +public sealed class StatusEffectCommand : ToolshedCommand +{ + private StatusEffectsSystem? _statusEffectsSystem; + + [CommandImplementation("add")] + public EntityUid? Add([PipedArgument] EntityUid input, [CommandArgument(typeof(StatusEffectCompletionParser))] EntProtoId status, float time, float delay = 0) + { + _statusEffectsSystem ??= GetSys(); + + _statusEffectsSystem.TryAddStatusEffectDuration( + input, + status, + TimeSpan.FromSeconds(time), + ZeroAsNull(delay)); + + return input; + } + + [CommandImplementation("add")] + public IEnumerable Add([PipedArgument] IEnumerable input, [CommandArgument(typeof(StatusEffectCompletionParser))] EntProtoId status, float time, float delay = 0) + { + _statusEffectsSystem ??= GetSys(); + + foreach (var ent in input) + { + _statusEffectsSystem.TryAddStatusEffectDuration( + ent, + status, + TimeSpan.FromSeconds(time), + ZeroAsNull(delay)); + + yield return ent; + } + } + + [CommandImplementation("update")] + public EntityUid? Update([PipedArgument] EntityUid input, [CommandArgument(typeof(StatusEffectCompletionParser))] EntProtoId status, float time, float delay = 0) + { + _statusEffectsSystem ??= GetSys(); + + _statusEffectsSystem.TryUpdateStatusEffectDuration( + input, + status, + ZeroAsNull(time), + ZeroAsNull(delay)); + + return input; + } + + [CommandImplementation("update")] + public IEnumerable Update([PipedArgument] IEnumerable input, [CommandArgument(typeof(StatusEffectCompletionParser))] EntProtoId status, float time, float delay = 0) + { + _statusEffectsSystem ??= GetSys(); + + foreach (var ent in input) + { + _statusEffectsSystem.TryUpdateStatusEffectDuration( + ent, + status, + ZeroAsNull(time), + ZeroAsNull(delay)); + + yield return ent; + } + } + + [CommandImplementation("set")] + public EntityUid? Set([PipedArgument] EntityUid input, [CommandArgument(typeof(StatusEffectCompletionParser))] EntProtoId status, float time = 0, float delay = 0) + { + _statusEffectsSystem ??= GetSys(); + + _statusEffectsSystem.TrySetStatusEffectDuration( + input, + status, + ZeroAsNull(time), + ZeroAsNull(delay)); + + return input; + } + + [CommandImplementation("set")] + public IEnumerable Set([PipedArgument] IEnumerable input, [CommandArgument(typeof(StatusEffectCompletionParser))] EntProtoId status, float time = 0, float delay = 0) + { + _statusEffectsSystem ??= GetSys(); + + foreach (var ent in input) + { + _statusEffectsSystem.TrySetStatusEffectDuration( + ent, + status, + ZeroAsNull(time), + ZeroAsNull(delay)); + + yield return ent; + } + } + + [CommandImplementation("remove")] + public EntityUid? Remove([PipedArgument] EntityUid input, [CommandArgument(typeof(StatusEffectCompletionParser))] EntProtoId status, float time = 0) + { + _statusEffectsSystem ??= GetSys(); + + _statusEffectsSystem.TryRemoveTime( + input, + status, + ZeroAsNull(time)); + + return input; + } + + [CommandImplementation("remove")] + public IEnumerable Remove([PipedArgument] IEnumerable input, [CommandArgument(typeof(StatusEffectCompletionParser))] EntProtoId status, float time = 0) + { + _statusEffectsSystem ??= GetSys(); + + foreach (var ent in input) + { + _statusEffectsSystem.TryRemoveTime( + ent, + status, + ZeroAsNull(time)); + + yield return ent; + } + } + + private static TimeSpan? ZeroAsNull(float delay) + { + return delay == 0 ? null : TimeSpan.FromSeconds(delay); + } +} diff --git a/Content.Server/Toolshed/TypeParsers/StatusEffects/StatusEffectCompletionParser.cs b/Content.Server/Toolshed/TypeParsers/StatusEffects/StatusEffectCompletionParser.cs new file mode 100644 index 0000000000..7faa7825d8 --- /dev/null +++ b/Content.Server/Toolshed/TypeParsers/StatusEffects/StatusEffectCompletionParser.cs @@ -0,0 +1,16 @@ +using Content.Shared.StatusEffectNew; +using Robust.Shared.Console; +using Robust.Shared.Prototypes; +using Robust.Shared.Toolshed; +using Robust.Shared.Toolshed.Syntax; +using Robust.Shared.Toolshed.TypeParsers; + +namespace Content.Server.Toolshed.TypeParsers.StatusEffects; + +public sealed class StatusEffectCompletionParser : CustomCompletionParser +{ + public override CompletionResult? TryAutocomplete(ParserContext ctx, CommandArgument? arg) + { + return CompletionResult.FromHintOptions(StatusEffectsSystem.StatusEffectPrototypes, GetArgHint(arg)); + } +} diff --git a/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs b/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs index 82915b002a..1c650e5e4c 100644 --- a/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs +++ b/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs @@ -14,6 +14,7 @@ namespace Content.Shared.StatusEffectNew; /// public sealed partial class StatusEffectsSystem : EntitySystem { + [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; @@ -22,6 +23,8 @@ public sealed partial class StatusEffectsSystem : EntitySystem private EntityQuery _containerQuery; private EntityQuery _effectQuery; + public static HashSet StatusEffectPrototypes = []; + public override void Initialize() { base.Initialize(); @@ -35,8 +38,12 @@ public sealed partial class StatusEffectsSystem : EntitySystem SubscribeLocalEvent>(OnRejuvenate); + SubscribeLocalEvent(OnPrototypesReloaded); + _containerQuery = GetEntityQuery(); _effectQuery = GetEntityQuery(); + + ReloadStatusEffectsCache(); } public override void Update(float frameTime) @@ -61,6 +68,25 @@ public sealed partial class StatusEffectsSystem : EntitySystem } } + private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) + { + if (!args.WasModified()) + return; + + ReloadStatusEffectsCache(); + } + + private void ReloadStatusEffectsCache() + { + StatusEffectPrototypes.Clear(); + + foreach (var ent in _proto.EnumeratePrototypes()) + { + if (ent.TryGetComponent(out _, _factory)) + StatusEffectPrototypes.Add(ent.ID); + } + } + private void OnStatusContainerInit(Entity ent, ref ComponentInit args) { ent.Comp.ActiveStatusEffects = diff --git a/Resources/Locale/en-US/commands/toolshed-commands.ftl b/Resources/Locale/en-US/commands/toolshed-commands.ftl index 85eae1ef3d..bfd2f780b1 100644 --- a/Resources/Locale/en-US/commands/toolshed-commands.ftl +++ b/Resources/Locale/en-US/commands/toolshed-commands.ftl @@ -6,9 +6,9 @@ command-description-acmd-perms = Returns the admin permissions of the given command, if any. command-description-acmd-caninvoke = Check if the given player can invoke the given command. -command-description-bank-accounts = +command-description-bank-accounts = Returns all accounts on a station. -command-description-bank-account = +command-description-bank-account = Returns a given bank account from a station. command-description-bank-adjust = Adjusts the money for the given bank account. @@ -166,3 +166,11 @@ command-description-dynamicrule-executenow = Executes the piped dynamic rule as if it had reached its regular update time. command-description-dynamicrule-rules = Gets a list of all the rules spawned by the piped dynamic rule. +command-description-statuseffect-add = + Adds time in seconds to a given status effect's duration, or creates one with a duration equal to time. +command-description-statuseffect-update = + Sets the duration of a status effect to the higher of the inputted time or existing time. If time is 0, duration will be infinite. +command-description-statuseffect-set = + Sets the duration of a status effect to the inputted time in seconds. If time is 0, duration will be infinite. +command-description-statuseffect-remove = + Removes a time from a given status effect by prototype. If time isn't set, removes the status effect. -- 2.52.0