Add methods to transfer actions between containers (#20901)

This commit is contained in:
Leon Friedrich
2023-10-12 04:50:10 +11:00
committed by GitHub
parent 8177c406f6
commit fcd0d9ef0f
3 changed files with 98 additions and 17 deletions

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Robust.Shared.Containers;
using Robust.Shared.Network;
using Robust.Shared.Timing;
@@ -15,6 +16,7 @@ public sealed class ActionContainerSystem : EntitySystem
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly INetManager _netMan = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
public override void Initialize()
{
@@ -96,7 +98,61 @@ public sealed class ActionContainerSystem : EntitySystem
}
/// <summary>
/// Adds a pre-existing action to an action container.
/// Transfers an action from one container to another, while keeping the attached entity the same.
/// </summary>
/// <remarks>
/// While the attached entity should be the same at the end, this will actually remove and then re-grant the action.
/// </remarks>
public void TransferAction(
EntityUid actionId,
EntityUid newContainer,
BaseActionComponent? action = null,
ActionsContainerComponent? container = null)
{
if (!_actions.ResolveActionData(actionId, ref action))
return;
if (action.Container == newContainer)
return;
var attached = action.AttachedEntity;
if (!AddAction(newContainer, actionId, action, container))
return;
DebugTools.AssertEqual(action.Container, newContainer);
DebugTools.AssertNull(action.AttachedEntity);
if (attached != null)
_actions.AddActionDirect(attached.Value, actionId, action: action);
DebugTools.AssertEqual(action.AttachedEntity, attached);
}
/// <summary>
/// Transfers all actions from one container to another, while keeping the attached entity the same.
/// </summary>
/// &lt;remarks&gt;
/// While the attached entity should be the same at the end, this will actually remove and then re-grant the action.
/// &lt;/remarks&gt;
public void TransferAllActions(
EntityUid from,
EntityUid to,
ActionsContainerComponent? oldContainer = null,
ActionsContainerComponent? newContainer = null)
{
if (!Resolve(from, ref oldContainer) || !Resolve(to, ref newContainer))
return;
foreach (var action in oldContainer.Container.ContainedEntities.ToArray())
{
TransferAction(action, to, container: newContainer);
}
DebugTools.AssertEqual(oldContainer.Container.Count, 0);
}
/// <summary>
/// Adds a pre-existing action to an action container. If the action is already in some container it will first remove it.
/// </summary>
public bool AddAction(EntityUid uid, EntityUid actionId, BaseActionComponent? action = null, ActionsContainerComponent? comp = null)
{
@@ -104,10 +160,7 @@ public sealed class ActionContainerSystem : EntitySystem
return false;
if (action.Container != null)
{
Log.Error($"Attempted to insert an action {ToPrettyString(actionId)} that was already in a container {ToPrettyString(action.Container.Value)}");
return false;
}
RemoveAction(actionId, action);
DebugTools.Assert(comp == null || comp.Owner == uid);
comp ??= EnsureComp<ActionsContainerComponent>(uid);
@@ -124,6 +177,35 @@ public sealed class ActionContainerSystem : EntitySystem
return true;
}
/// <summary>
/// Removes an action from its container and any action-performer and moves the action to null-space
/// </summary>
public void RemoveAction(EntityUid actionId, BaseActionComponent? action = null)
{
if (!_actions.ResolveActionData(actionId, ref action))
return;
if (action.Container == null)
return;
_transform.DetachParentToNull(actionId, Transform(actionId));
// Container removal events should have removed the action from the action container.
// However, just in case the container was already deleted we will still manually clear the container field
if (action.Container != null)
{
if (Exists(action.Container))
Log.Error($"Failed to remove action {ToPrettyString(actionId)} from its container {ToPrettyString(action.Container)}?");
action.Container = null;
}
// If the action was granted to some entity, then the removal from the container should have automatically removed it.
// However, if the action was granted without ever being placed in an action container, it will not have been removed.
// Therefore, to ensure that the behaviour of the method is consistent we will also explicitly remove the action.
if (action.AttachedEntity != null)
_actions.RemoveAction(action.AttachedEntity.Value, actionId, action: action);
}
private void OnInit(EntityUid uid, ActionsContainerComponent component, ComponentInit args)
{
component.Container = _container.EnsureContainer<Container>(uid, ActionsContainerComponent.ContainerId);
@@ -171,13 +253,7 @@ public sealed class ActionContainerSystem : EntitySystem
var ev = new ActionRemovedEvent(args.Entity, data);
RaiseLocalEvent(uid, ref ev);
if (_netMan.IsServer)
{
// TODO Actions
// log an error or warning here once gibbing code is fixed.
QueueDel(args.Entity);
}
data.Container = null;
}
}