Action charges refactor (#33993)

* Action charges refactor

- Fixes the slight godmoding of baseactioncomponent.
- Gets back 1ms of server time.

* chorg

* Remove FrameUpdate

* Fixes

* More fixes

* Combine

* Fixes

* Updates

* weh

* Last fixes

* weh

* Fix naughty

* YAML fixes

* This one too

* Merge conflicts

* This thing

* Review

* Fix this as well

* Icon fix

* weh

* Review

* Review

* seamless

* Review
This commit is contained in:
metalgearsloth
2025-04-18 13:45:48 +10:00
committed by GitHub
parent 424f153142
commit 7d2ef2bd47
30 changed files with 366 additions and 399 deletions

View File

@@ -21,14 +21,14 @@ namespace Content.Shared.Actions;
public abstract class SharedActionsSystem : EntitySystem
{
[Dependency] protected readonly IGameTiming GameTiming = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
public override void Initialize()
{
@@ -69,47 +69,9 @@ public abstract class SharedActionsSystem : EntitySystem
SubscribeAllEvent<RequestPerformActionEvent>(OnActionRequest);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var worldActionQuery = EntityQueryEnumerator<WorldTargetActionComponent>();
while (worldActionQuery.MoveNext(out var uid, out var action))
{
if (IsCooldownActive(action) || !ShouldResetCharges(action))
continue;
ResetCharges(uid, dirty: true);
}
var instantActionQuery = EntityQueryEnumerator<InstantActionComponent>();
while (instantActionQuery.MoveNext(out var uid, out var action))
{
if (IsCooldownActive(action) || !ShouldResetCharges(action))
continue;
ResetCharges(uid, dirty: true);
}
var entityActionQuery = EntityQueryEnumerator<EntityTargetActionComponent>();
while (entityActionQuery.MoveNext(out var uid, out var action))
{
if (IsCooldownActive(action) || !ShouldResetCharges(action))
continue;
ResetCharges(uid, dirty: true);
}
}
private void OnActionMapInit(EntityUid uid, BaseActionComponent component, MapInitEvent args)
{
component.OriginalIconColor = component.IconColor;
if (component.Charges == null)
return;
component.MaxCharges ??= component.Charges.Value;
Dirty(uid, component);
}
private void OnActionShutdown(EntityUid uid, BaseActionComponent component, ComponentShutdown args)
@@ -312,68 +274,6 @@ public abstract class SharedActionsSystem : EntitySystem
Dirty(actionId.Value, action);
}
public void SetCharges(EntityUid? actionId, int? charges)
{
if (!TryGetActionData(actionId, out var action) ||
action.Charges == charges)
{
return;
}
action.Charges = charges;
UpdateAction(actionId, action);
Dirty(actionId.Value, action);
}
public int? GetCharges(EntityUid? actionId)
{
if (!TryGetActionData(actionId, out var action))
return null;
return action.Charges;
}
public void AddCharges(EntityUid? actionId, int addCharges)
{
if (!TryGetActionData(actionId, out var action) || action.Charges == null || addCharges < 1)
return;
action.Charges += addCharges;
UpdateAction(actionId, action);
Dirty(actionId.Value, action);
}
public void RemoveCharges(EntityUid? actionId, int? removeCharges)
{
if (!TryGetActionData(actionId, out var action) || action.Charges == null)
return;
if (removeCharges == null)
action.Charges = removeCharges;
else
action.Charges -= removeCharges;
if (action.Charges is < 0)
action.Charges = null;
UpdateAction(actionId, action);
Dirty(actionId.Value, action);
}
public void ResetCharges(EntityUid? actionId, bool update = false, bool dirty = false)
{
if (!TryGetActionData(actionId, out var action))
return;
action.Charges = action.MaxCharges;
if (update)
UpdateAction(actionId, action);
if (dirty)
Dirty(actionId.Value, action);
}
private void OnActionsGetState(EntityUid uid, ActionsComponent component, ref ComponentGetState args)
{
args.State = new ActionsComponentState(GetNetEntitySet(component.Actions));
@@ -416,6 +316,10 @@ public abstract class SharedActionsSystem : EntitySystem
if (!action.Enabled)
return;
var curTime = GameTiming.CurTime;
if (IsCooldownActive(action, curTime))
return;
// check for action use prevention
// TODO: make code below use this event with a dedicated component
var attemptEv = new ActionAttemptEvent(user);
@@ -423,14 +327,6 @@ public abstract class SharedActionsSystem : EntitySystem
if (attemptEv.Cancelled)
return;
var curTime = GameTiming.CurTime;
if (IsCooldownActive(action, curTime))
return;
// TODO: Replace with individual charge recovery when we have the visuals to aid it
if (action is { Charges: < 1, RenewCharges: true })
ResetCharges(actionEnt, true, true);
BaseActionEvent? performEvent = null;
if (action.CheckConsciousness && !_actionBlockerSystem.CanConsciouslyPerformAction(user))
@@ -705,16 +601,8 @@ public abstract class SharedActionsSystem : EntitySystem
var dirty = toggledBefore != action.Toggled;
if (action.Charges != null)
{
dirty = true;
action.Charges--;
if (action is { Charges: 0, RenewCharges: false })
action.Enabled = false;
}
action.Cooldown = null;
if (action is { UseDelay: not null, Charges: null or < 1 })
if (action is { UseDelay: not null})
{
dirty = true;
action.Cooldown = (curTime, curTime + action.UseDelay.Value);
@@ -1014,8 +902,6 @@ public abstract class SharedActionsSystem : EntitySystem
if (!action.Enabled)
return false;
if (action.Charges.HasValue && action.Charges <= 0)
return false;
var curTime = GameTiming.CurTime;
if (action.Cooldown.HasValue && action.Cooldown.Value.End > curTime)
@@ -1125,15 +1011,9 @@ public abstract class SharedActionsSystem : EntitySystem
/// <summary>
/// Checks if the action has a cooldown and if it's still active
/// </summary>
protected bool IsCooldownActive(BaseActionComponent action, TimeSpan? curTime = null)
public bool IsCooldownActive(BaseActionComponent action, TimeSpan? curTime = null)
{
curTime ??= GameTiming.CurTime;
// TODO: Check for charge recovery timer
return action.Cooldown.HasValue && action.Cooldown.Value.End > curTime;
}
protected bool ShouldResetCharges(BaseActionComponent action)
{
return action is { Charges: < 1, RenewCharges: true };
}
}