do_after (#1616)
* do_after Ports (most of) do_after from SS13. Callers are expected to await the DoAfter task from the DoAfterSystem. I had a dummy component for in-game testing which I removed for the PR so nothing in game uses do_after at the moment. Currently only the movement cancellation is predicted client-side. * Minor do_after doc cleanup * do_the_shuffle Fix nullable build errors. * The last nullable * Implement NeedHand Thanks zum. * nullable dereference * Adjust the system query Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
This commit is contained in:
88
Content.Client/GameObjects/Components/DoAfterComponent.cs
Normal file
88
Content.Client/GameObjects/Components/DoAfterComponent.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.GameObjects.EntitySystems.DoAfter;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class DoAfterComponent : SharedDoAfterComponent
|
||||
{
|
||||
public override string Name => "DoAfter";
|
||||
|
||||
public IReadOnlyDictionary<byte, DoAfterMessage> DoAfters => _doAfters;
|
||||
private readonly Dictionary<byte, DoAfterMessage> _doAfters = new Dictionary<byte, DoAfterMessage>();
|
||||
|
||||
public readonly List<(TimeSpan CancelTime, DoAfterMessage Message)> CancelledDoAfters =
|
||||
new List<(TimeSpan CancelTime, DoAfterMessage Message)>();
|
||||
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null)
|
||||
{
|
||||
base.HandleNetworkMessage(message, netChannel, session);
|
||||
switch (message)
|
||||
{
|
||||
case DoAfterMessage msg:
|
||||
_doAfters.Add(msg.ID, msg);
|
||||
EntitySystem.Get<DoAfterSystem>().Gui?.AddDoAfter(msg);
|
||||
break;
|
||||
case CancelledDoAfterMessage msg:
|
||||
Cancel(msg.ID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a DoAfter without showing a cancellation graphic.
|
||||
/// </summary>
|
||||
/// <param name="doAfter"></param>
|
||||
public void Remove(DoAfterMessage doAfter)
|
||||
{
|
||||
if (_doAfters.ContainsKey(doAfter.ID))
|
||||
{
|
||||
_doAfters.Remove(doAfter.ID);
|
||||
}
|
||||
|
||||
for (var i = CancelledDoAfters.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var cancelled = CancelledDoAfters[i];
|
||||
|
||||
if (cancelled.Message == doAfter)
|
||||
{
|
||||
CancelledDoAfters.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EntitySystem.Get<DoAfterSystem>().Gui?.RemoveDoAfter(doAfter.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark a DoAfter as cancelled and show a cancellation graphic.
|
||||
/// </summary>
|
||||
/// Actual removal is handled by DoAfterEntitySystem.
|
||||
/// <param name="id"></param>
|
||||
/// <param name="currentTime"></param>
|
||||
public void Cancel(byte id, TimeSpan? currentTime = null)
|
||||
{
|
||||
foreach (var (_, cancelled) in CancelledDoAfters)
|
||||
{
|
||||
if (cancelled.ID == id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var doAfterMessage = _doAfters[id];
|
||||
currentTime ??= IoCManager.Resolve<IGameTiming>().CurTime;
|
||||
CancelledDoAfters.Add((currentTime.Value, doAfterMessage));
|
||||
EntitySystem.Get<DoAfterSystem>().Gui?.CancelDoAfter(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user