Dumpable component to use a doafter to empty storage into a disposal unit, placeable surface, or the ground (#7792)

This commit is contained in:
Rane
2022-05-03 23:00:22 -04:00
committed by GitHub
parent 40ae7cc285
commit cfd00e74ca
11 changed files with 240 additions and 72 deletions

View File

@@ -0,0 +1,193 @@
using System.Threading;
using Content.Shared.Interaction;
using Content.Server.Storage.Components;
using Content.Shared.Storage.Components;
using Content.Shared.Verbs;
using Content.Server.Disposal.Unit.Components;
using Content.Server.Disposal.Unit.EntitySystems;
using Content.Server.DoAfter;
using Content.Shared.Placeable;
using Content.Server.Hands.Systems;
using Robust.Shared.Containers;
namespace Content.Server.Storage.EntitySystems
{
public sealed class DumpableSystem : EntitySystem
{
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly DisposalUnitSystem _disposalUnitSystem = default!;
[Dependency] private readonly HandsSystem _handsSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DumpableComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<DumpableComponent, GetVerbsEvent<AlternativeVerb>>(AddDumpVerb);
SubscribeLocalEvent<DumpableComponent, GetVerbsEvent<UtilityVerb>>(AddUtilityVerbs);
SubscribeLocalEvent<DumpCompletedEvent>(OnDumpCompleted);
SubscribeLocalEvent<DumpCancelledEvent>(OnDumpCancelled);
}
private void OnAfterInteract(EntityUid uid, DumpableComponent component, AfterInteractEvent args)
{
if (!args.CanReach)
return;
if (!TryComp<ServerStorageComponent>(args.Used, out var storage))
return;
if (storage.StoredEntities == null || storage.StoredEntities.Count == 0)
return;
if (HasComp<DisposalUnitComponent>(args.Target) || HasComp<PlaceableSurfaceComponent>(args.Target))
{
StartDoAfter(uid, args.Target.Value, args.User, component, storage);
return;
}
}
private void AddDumpVerb(EntityUid uid, DumpableComponent dumpable, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;
if (!TryComp<ServerStorageComponent>(uid, out var storage) || storage.StoredEntities == null || storage.StoredEntities.Count == 0)
return;
AlternativeVerb verb = new()
{
Act = () =>
{
StartDoAfter(uid, null, args.User, dumpable, storage, 0.6f);
},
Text = Loc.GetString("dump-verb-name"),
IconTexture = "/Textures/Interface/VerbIcons/drop.svg.192dpi.png",
};
args.Verbs.Add(verb);
}
private void AddUtilityVerbs(EntityUid uid, DumpableComponent dumpable, GetVerbsEvent<UtilityVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;
if (!TryComp<ServerStorageComponent>(uid, out var storage) || storage.StoredEntities == null || storage.StoredEntities.Count == 0)
return;
if (HasComp<DisposalUnitComponent>(args.Target))
{
UtilityVerb verb = new()
{
Act = () =>
{
StartDoAfter(uid, args.Target, args.User, dumpable, storage);
},
Text = Loc.GetString("dump-disposal-verb-name", ("unit", args.Target)),
IconEntity = uid
};
args.Verbs.Add(verb);
}
if (HasComp<PlaceableSurfaceComponent>(args.Target))
{
UtilityVerb verb = new()
{
Act = () =>
{
StartDoAfter(uid, args.Target, args.User, dumpable, storage);
},
Text = Loc.GetString("dump-placeable-verb-name", ("surface", args.Target)),
IconEntity = uid
};
args.Verbs.Add(verb);
}
}
private void StartDoAfter(EntityUid storageUid, EntityUid? targetUid, EntityUid userUid, DumpableComponent dumpable, ServerStorageComponent storage, float multiplier = 1)
{
if (dumpable.CancelToken != null)
{
dumpable.CancelToken.Cancel();
dumpable.CancelToken = null;
return;
}
if (storage.StoredEntities == null)
return;
float delay = storage.StoredEntities.Count * (float) dumpable.DelayPerItem.TotalSeconds * multiplier;
dumpable.CancelToken = new CancellationTokenSource();
_doAfterSystem.DoAfter(new DoAfterEventArgs(userUid, delay, dumpable.CancelToken.Token, target: targetUid)
{
BroadcastFinishedEvent = new DumpCompletedEvent(userUid, targetUid, storage.StoredEntities),
BroadcastCancelledEvent = new DumpCancelledEvent(dumpable.Owner),
BreakOnTargetMove = true,
BreakOnUserMove = true,
BreakOnStun = true,
NeedHand = true
});
}
private void OnDumpCompleted(DumpCompletedEvent args)
{
Queue<EntityUid> dumpQueue = new();
foreach (var entity in args.StoredEntities)
{
dumpQueue.Enqueue(entity);
}
if (TryComp<DisposalUnitComponent>(args.Target, out var disposal))
{
foreach (var entity in dumpQueue)
{
_disposalUnitSystem.DoInsertDisposalUnit(args.Target.Value, entity);
}
return;
}
foreach (var entity in dumpQueue)
{
Transform(entity).AttachParentToContainerOrGrid(EntityManager);
}
if (HasComp<PlaceableSurfaceComponent>(args.Target))
{
foreach (var entity in dumpQueue)
{
Transform(entity).LocalPosition = Transform(args.Target.Value).LocalPosition;
}
return;
}
}
private void OnDumpCancelled(DumpCancelledEvent args)
{
if (TryComp<DumpableComponent>(args.Uid, out var dumpable))
dumpable.CancelToken = null;
}
private sealed class DumpCancelledEvent : EntityEventArgs
{
public readonly EntityUid Uid;
public DumpCancelledEvent(EntityUid uid)
{
Uid = uid;
}
}
private sealed class DumpCompletedEvent : EntityEventArgs
{
public EntityUid User { get; }
public EntityUid? Target { get; }
public IReadOnlyList<EntityUid> StoredEntities { get; }
public DumpCompletedEvent(EntityUid user, EntityUid? target, IReadOnlyList<EntityUid> storedEntities)
{
User = user;
Target = target;
StoredEntities = storedEntities;
}
}
}
}

View File

@@ -175,19 +175,6 @@ namespace Content.Server.Storage.EntitySystems
args.Verbs.Add(verb);
}
// if the target is a disposal unit, add a verb to transfer storage into the unit (e.g., empty a trash bag).
if (!TryComp(args.Target, out DisposalUnitComponent? disposal))
return;
UtilityVerb dispose = new()
{
Text = Loc.GetString("storage-component-dispose-verb"),
IconEntity = args.Using,
Act = () => DisposeEntities(args.User, uid, args.Target, component, lockComponent, disposal)
};
args.Verbs.Add(dispose);
}
@@ -446,35 +433,6 @@ namespace Content.Server.Storage.EntitySystems
UpdateStorageUI(source, sourceComp);
}
/// <summary>
/// Move entities from storage into a disposal unit.
/// </summary>
public void DisposeEntities(EntityUid user, EntityUid source, EntityUid target,
ServerStorageComponent? sourceComp = null, LockComponent? sourceLock = null,
DisposalUnitComponent? disposalComp = null)
{
if (!Resolve(source, ref sourceComp) || !Resolve(target, ref disposalComp))
return;
var entities = sourceComp.Storage?.ContainedEntities;
if (entities == null || entities.Count == 0)
return;
if (Resolve(source, ref sourceLock, false) && sourceLock.Locked)
return;
foreach (var entity in entities.ToList())
{
if (_disposalSystem.CanInsert(disposalComp, entity)
&& disposalComp.Container.Insert(entity))
{
_disposalSystem.AfterInsert(disposalComp, entity);
}
}
RecalculateStorageUsed(sourceComp);
UpdateStorageUI(source, sourceComp);
}
public void HandleRemoveEntity(EntityUid uid, EntityUid player, EntityUid itemToRemove, ServerStorageComponent? storageComp = null)
{
if (!Resolve(uid, ref storageComp))