Add post-checks for do_after (#1940)

* Add post-checks for do_after

So you can do InRangeUnobstructed or whatever at the end.

Individual components should do their own check upfront to avoid the state ever being sent. I added a pre-made function for people to do InRangeUnobstructed.

* Woops imports

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
This commit is contained in:
metalgearsloth
2020-08-29 21:35:03 +10:00
committed by GitHub
parent b993ebb30a
commit 65a9a09049
2 changed files with 44 additions and 3 deletions

View File

@@ -1,7 +1,6 @@
#nullable enable
using System;
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Damage;
using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.GameObjects.Components.Mobs;
@@ -86,7 +85,16 @@ namespace Content.Server.GameObjects.EntitySystems.DoAfter
if (IsFinished())
{
Tcs.SetResult(DoAfterStatus.Finished);
// Do the final checks here
if (!TryPostCheck())
{
Tcs.SetResult(DoAfterStatus.Cancelled);
}
else
{
Tcs.SetResult(DoAfterStatus.Finished);
}
return;
}
@@ -98,6 +106,11 @@ namespace Content.Server.GameObjects.EntitySystems.DoAfter
private bool IsCancelled()
{
if (EventArgs.User.Deleted || EventArgs.Target?.Deleted == true)
{
return true;
}
//https://github.com/tgstation/tgstation/blob/1aa293ea337283a0191140a878eeba319221e5df/code/__HELPERS/mobs.dm
if (EventArgs.CancelToken.IsCancellationRequested)
{
@@ -157,10 +170,15 @@ namespace Content.Server.GameObjects.EntitySystems.DoAfter
}
}
}
return false;
}
private bool TryPostCheck()
{
return EventArgs.PostCheck?.Invoke() != false;
}
private bool IsFinished()
{
if (Elapsed <= EventArgs.Delay)

View File

@@ -1,6 +1,9 @@
#nullable enable
using System;
using System.Threading;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Physics;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
// ReSharper disable UnassignedReadonlyField
@@ -9,6 +12,18 @@ namespace Content.Server.GameObjects.EntitySystems.DoAfter
{
public sealed class DoAfterEventArgs
{
// Premade checks
public Func<bool> GetInRangeUnobstructed(int collisionMask = (int) CollisionGroup.MobMask)
{
if (Target == null)
{
throw new InvalidOperationException("Can't supply a null target to DoAfterEventArgs.GetInRangeUnobstructed");
}
var interactionSystem = EntitySystem.Get<SharedInteractionSystem>();
Func<IEntity, bool> ignored = entity => entity == User || entity == Target;
return () => interactionSystem.InRangeUnobstructed(User.Transform.MapPosition, Target.Transform.MapPosition, collisionMask: collisionMask, predicate: ignored);
}
/// <summary>
/// The entity invoking do_after
/// </summary>
@@ -49,6 +64,14 @@ namespace Content.Server.GameObjects.EntitySystems.DoAfter
public bool BreakOnDamage { get; set; }
public bool BreakOnStun { get; set; }
/// <summary>
/// Requires a function call once at the end (like InRangeUnobstructed).
/// </summary>
/// <remarks>
/// Anything that needs a pre-check should do it itself so no DoAfterState is ever sent to the client.
/// </remarks>
public Func<bool>? PostCheck { get; set; } = null;
/// <summary>
/// Additional conditions that need to be met. Return false to cancel.
/// </summary>