From ef958185fbe12fcb7156426a1adf4a23521141fb Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com> Date: Sun, 4 Jul 2021 13:32:24 +0200 Subject: [PATCH] DoAfter can now raise events so you don't need to use async with it (#4253) --- .../Tests/DoAfter/DoAfterServerTest.cs | 4 +- .../Surgery/BiologicalSurgeryDataComponent.cs | 2 +- .../Climbing/Components/ClimbableComponent.cs | 4 +- .../Components/ConstructionComponent.cs | 4 +- .../Construction/ConstructionSystem.cs | 2 +- .../Cuffs/Components/CuffableComponent.cs | 2 +- .../Cuffs/Components/HandcuffComponent.cs | 2 +- .../Mailing/DisposalMailingUnitComponent.cs | 2 +- .../Unit/Components/DisposalUnitComponent.cs | 2 +- Content.Server/DoAfter/DoAfter.cs | 3 +- Content.Server/DoAfter/DoAfterEventArgs.cs | 30 +++++++++ Content.Server/DoAfter/DoAfterSystem.cs | 63 +++++++++++++++---- .../DisassembleOnActivateSystem.cs | 2 +- .../EntitySystems/SpawnAfterInteractSystem.cs | 2 +- .../Fluids/Components/BucketComponent.cs | 2 +- .../Fluids/Components/MopComponent.cs | 2 +- .../Components/KitchenSpikeComponent.cs | 2 +- Content.Server/RCD/Components/RCDComponent.cs | 2 +- .../Components/ServerStorageComponent.cs | 2 +- Content.Server/Strip/StrippableComponent.cs | 8 +-- .../Tools/Components/ToolComponent.cs | 2 +- 21 files changed, 106 insertions(+), 38 deletions(-) diff --git a/Content.IntegrationTests/Tests/DoAfter/DoAfterServerTest.cs b/Content.IntegrationTests/Tests/DoAfter/DoAfterServerTest.cs index 16ef7b43c9..570178cf44 100644 --- a/Content.IntegrationTests/Tests/DoAfter/DoAfterServerTest.cs +++ b/Content.IntegrationTests/Tests/DoAfter/DoAfterServerTest.cs @@ -39,7 +39,7 @@ namespace Content.IntegrationTests.Tests.DoAfter var mob = entityManager.SpawnEntity("Dummy", MapCoordinates.Nullspace); var cancelToken = new CancellationTokenSource(); var args = new DoAfterEventArgs(mob, tickTime / 2, cancelToken.Token); - task = EntitySystem.Get().DoAfter(args); + task = EntitySystem.Get().WaitDoAfter(args); }); await server.WaitRunTicks(1); @@ -62,7 +62,7 @@ namespace Content.IntegrationTests.Tests.DoAfter var mob = entityManager.SpawnEntity("Dummy", MapCoordinates.Nullspace); var cancelToken = new CancellationTokenSource(); var args = new DoAfterEventArgs(mob, tickTime * 2, cancelToken.Token); - task = EntitySystem.Get().DoAfter(args); + task = EntitySystem.Get().WaitDoAfter(args); cancelToken.Cancel(); }); diff --git a/Content.Server/Body/Surgery/BiologicalSurgeryDataComponent.cs b/Content.Server/Body/Surgery/BiologicalSurgeryDataComponent.cs index b6db086dc7..5d932a611f 100644 --- a/Content.Server/Body/Surgery/BiologicalSurgeryDataComponent.cs +++ b/Content.Server/Body/Surgery/BiologicalSurgeryDataComponent.cs @@ -68,7 +68,7 @@ namespace Content.Server.Body.Surgery BreakOnTargetMove = true }; - return await doAfterSystem.DoAfter(args) == DoAfterStatus.Finished; + return await doAfterSystem.WaitDoAfter(args) == DoAfterStatus.Finished; } private bool HasIncisionNotClamped() diff --git a/Content.Server/Climbing/Components/ClimbableComponent.cs b/Content.Server/Climbing/Components/ClimbableComponent.cs index 5b928cdf54..e8033f269d 100644 --- a/Content.Server/Climbing/Components/ClimbableComponent.cs +++ b/Content.Server/Climbing/Components/ClimbableComponent.cs @@ -157,7 +157,7 @@ namespace Content.Server.Climbing.Components BreakOnStun = true }; - var result = await EntitySystem.Get().DoAfter(doAfterEventArgs); + var result = await EntitySystem.Get().WaitDoAfter(doAfterEventArgs); if (result != DoAfterStatus.Cancelled && entityToMove.TryGetComponent(out PhysicsComponent? body) && body.Fixtures.Count >= 1) { @@ -204,7 +204,7 @@ namespace Content.Server.Climbing.Components BreakOnStun = true }; - var result = await EntitySystem.Get().DoAfter(doAfterEventArgs); + var result = await EntitySystem.Get().WaitDoAfter(doAfterEventArgs); if (result != DoAfterStatus.Cancelled && user.TryGetComponent(out PhysicsComponent? body) && body.Fixtures.Count >= 1) { diff --git a/Content.Server/Construction/Components/ConstructionComponent.cs b/Content.Server/Construction/Components/ConstructionComponent.cs index 8b86182e5a..a4de447e4c 100644 --- a/Content.Server/Construction/Components/ConstructionComponent.cs +++ b/Content.Server/Construction/Components/ConstructionComponent.cs @@ -258,7 +258,7 @@ namespace Content.Server.Construction.Components { case ArbitraryInsertConstructionGraphStep arbitraryStep: if (arbitraryStep.EntityValid(eventArgs.Using) - && await doAfterSystem.DoAfter(doAfterArgs) == DoAfterStatus.Finished) + && await doAfterSystem.WaitDoAfter(doAfterArgs) == DoAfterStatus.Finished) { valid = true; } @@ -267,7 +267,7 @@ namespace Content.Server.Construction.Components case MaterialConstructionGraphStep materialStep: if (materialStep.EntityValid(eventArgs.Using, out var stack) - && await doAfterSystem.DoAfter(doAfterArgs) == DoAfterStatus.Finished) + && await doAfterSystem.WaitDoAfter(doAfterArgs) == DoAfterStatus.Finished) { var splitStack = EntitySystem.Get().Split(eventArgs.Using.Uid, stack, materialStep.Amount, eventArgs.User.Transform.Coordinates); diff --git a/Content.Server/Construction/ConstructionSystem.cs b/Content.Server/Construction/ConstructionSystem.cs index c18701866f..4b4bcaab3c 100644 --- a/Content.Server/Construction/ConstructionSystem.cs +++ b/Content.Server/Construction/ConstructionSystem.cs @@ -238,7 +238,7 @@ namespace Content.Server.Construction NeedHand = false, }; - if (await doAfterSystem.DoAfter(doAfterArgs) == DoAfterStatus.Cancelled) + if (await doAfterSystem.WaitDoAfter(doAfterArgs) == DoAfterStatus.Cancelled) { FailCleanup(); return null; diff --git a/Content.Server/Cuffs/Components/CuffableComponent.cs b/Content.Server/Cuffs/Components/CuffableComponent.cs index 7fc5d27503..4293558043 100644 --- a/Content.Server/Cuffs/Components/CuffableComponent.cs +++ b/Content.Server/Cuffs/Components/CuffableComponent.cs @@ -253,7 +253,7 @@ namespace Content.Server.Cuffs.Components var doAfterSystem = EntitySystem.Get(); _uncuffing = true; - var result = await doAfterSystem.DoAfter(doAfterEventArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterEventArgs); _uncuffing = false; diff --git a/Content.Server/Cuffs/Components/HandcuffComponent.cs b/Content.Server/Cuffs/Components/HandcuffComponent.cs index 66fd797321..bac2720916 100644 --- a/Content.Server/Cuffs/Components/HandcuffComponent.cs +++ b/Content.Server/Cuffs/Components/HandcuffComponent.cs @@ -214,7 +214,7 @@ namespace Content.Server.Cuffs.Components _cuffing = true; - var result = await EntitySystem.Get().DoAfter(doAfterEventArgs); + var result = await EntitySystem.Get().WaitDoAfter(doAfterEventArgs); _cuffing = false; diff --git a/Content.Server/Disposal/Mailing/DisposalMailingUnitComponent.cs b/Content.Server/Disposal/Mailing/DisposalMailingUnitComponent.cs index af7225fd4a..806ca63dec 100644 --- a/Content.Server/Disposal/Mailing/DisposalMailingUnitComponent.cs +++ b/Content.Server/Disposal/Mailing/DisposalMailingUnitComponent.cs @@ -217,7 +217,7 @@ namespace Content.Server.Disposal.Mailing NeedHand = false, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result == DoAfterStatus.Cancelled) return false; diff --git a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs index 25075c8be7..7d483e4399 100644 --- a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs +++ b/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs @@ -196,7 +196,7 @@ namespace Content.Server.Disposal.Unit.Components NeedHand = false, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result == DoAfterStatus.Cancelled) return false; diff --git a/Content.Server/DoAfter/DoAfter.cs b/Content.Server/DoAfter/DoAfter.cs index 3c41363818..4b929a060b 100644 --- a/Content.Server/DoAfter/DoAfter.cs +++ b/Content.Server/DoAfter/DoAfter.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Content.Server.Hands.Components; using Content.Server.Items; using Content.Server.Stunnable.Components; +using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Timing; @@ -16,7 +17,7 @@ namespace Content.Server.DoAfter private TaskCompletionSource Tcs { get; } - public DoAfterEventArgs EventArgs; + public readonly DoAfterEventArgs EventArgs; public TimeSpan StartTime { get; } diff --git a/Content.Server/DoAfter/DoAfterEventArgs.cs b/Content.Server/DoAfter/DoAfterEventArgs.cs index b7ec522f5c..c4291fdc9c 100644 --- a/Content.Server/DoAfter/DoAfterEventArgs.cs +++ b/Content.Server/DoAfter/DoAfterEventArgs.cs @@ -81,6 +81,36 @@ namespace Content.Server.DoAfter /// public Func? ExtraCheck { get; set; } + /// + /// Event to be raised directed to the entity when the DoAfter is cancelled. + /// + public EntityEventArgs? UserCancelledEvent { get; set; } + + /// + /// Event to be raised directed to the entity when the DoAfter is finished successfully. + /// + public EntityEventArgs? UserFinishedEvent { get; set; } + + /// + /// Event to be raised directed to the entity when the DoAfter is cancelled. + /// + public EntityEventArgs? TargetCancelledEvent { get; set; } + + /// + /// Event to be raised directed to the entity when the DoAfter is finished successfully. + /// + public EntityEventArgs? TargetFinishedEvent { get; set; } + + /// + /// Event to be broadcast when the DoAfter is cancelled. + /// + public object? BroadcastCancelledEvent { get; set; } + + /// + /// Event to be broadcast when the DoAfter is finished successfully. + /// + public object? BroadcastFinishedEvent { get; set; } + public DoAfterEventArgs( IEntity user, float delay, diff --git a/Content.Server/DoAfter/DoAfterSystem.cs b/Content.Server/DoAfter/DoAfterSystem.cs index 8ee9372983..6934a93c61 100644 --- a/Content.Server/DoAfter/DoAfterSystem.cs +++ b/Content.Server/DoAfter/DoAfterSystem.cs @@ -11,15 +11,16 @@ namespace Content.Server.DoAfter [UsedImplicitly] public sealed class DoAfterSystem : EntitySystem { + // We cache these lists as to not allocate them every update tick... + private readonly List _cancelled = new(); + private readonly List _finished = new(); + public override void Update(float frameTime) { base.Update(frameTime); foreach (var comp in ComponentManager.EntityQuery(true)) { - var cancelled = new List(0); - var finished = new List(0); - foreach (var doAfter in comp.DoAfters.ToArray()) { doAfter.Run(frameTime); @@ -29,27 +30,47 @@ namespace Content.Server.DoAfter case DoAfterStatus.Running: break; case DoAfterStatus.Cancelled: - cancelled.Add(doAfter); + _cancelled.Add(doAfter); break; case DoAfterStatus.Finished: - finished.Add(doAfter); + _finished.Add(doAfter); break; default: throw new ArgumentOutOfRangeException(); } } - foreach (var doAfter in cancelled) + foreach (var doAfter in _cancelled) { comp.Cancelled(doAfter); + + if(!doAfter.EventArgs.User.Deleted && doAfter.EventArgs.UserCancelledEvent != null) + RaiseLocalEvent(doAfter.EventArgs.User.Uid, doAfter.EventArgs.UserCancelledEvent, false); + + if(doAfter.EventArgs.Target is { Deleted: false } && doAfter.EventArgs.TargetCancelledEvent != null) + RaiseLocalEvent(doAfter.EventArgs.Target.Uid, doAfter.EventArgs.TargetCancelledEvent, false); + + if(doAfter.EventArgs.BroadcastCancelledEvent != null) + RaiseLocalEvent(doAfter.EventArgs.BroadcastCancelledEvent); } - foreach (var doAfter in finished) + foreach (var doAfter in _finished) { comp.Finished(doAfter); + + if(!doAfter.EventArgs.User.Deleted && doAfter.EventArgs.UserFinishedEvent != null) + RaiseLocalEvent(doAfter.EventArgs.User.Uid, doAfter.EventArgs.UserFinishedEvent, false); + + if(doAfter.EventArgs.Target is { Deleted: false } && doAfter.EventArgs.TargetFinishedEvent != null) + RaiseLocalEvent(doAfter.EventArgs.Target.Uid, doAfter.EventArgs.TargetFinishedEvent, false); + + if(doAfter.EventArgs.BroadcastFinishedEvent != null) + RaiseLocalEvent(doAfter.EventArgs.BroadcastFinishedEvent); } - finished.Clear(); + // Clean the shared lists at the end, ensuring they'll be clean for the next time we need them. + _cancelled.Clear(); + _finished.Clear(); } } @@ -59,17 +80,33 @@ namespace Content.Server.DoAfter /// /// /// - public async Task DoAfter(DoAfterEventArgs eventArgs) + public async Task WaitDoAfter(DoAfterEventArgs eventArgs) + { + var doAfter = CreateDoAfter(eventArgs); + + await doAfter.AsTask; + + return doAfter.Status; + } + + /// + /// Creates a DoAfter without waiting for it to finish. You can use events with this. + /// These can be potentially cancelled by the user moving or when other things happen. + /// + /// + public void DoAfter(DoAfterEventArgs eventArgs) + { + CreateDoAfter(eventArgs); + } + + private DoAfter CreateDoAfter(DoAfterEventArgs eventArgs) { // Setup var doAfter = new DoAfter(eventArgs); // Caller's gonna be responsible for this I guess var doAfterComponent = eventArgs.User.GetComponent(); doAfterComponent.Add(doAfter); - - await doAfter.AsTask; - - return doAfter.Status; + return doAfter; } } diff --git a/Content.Server/Engineering/EntitySystems/DisassembleOnActivateSystem.cs b/Content.Server/Engineering/EntitySystems/DisassembleOnActivateSystem.cs index b123077e94..7dedae6d28 100644 --- a/Content.Server/Engineering/EntitySystems/DisassembleOnActivateSystem.cs +++ b/Content.Server/Engineering/EntitySystems/DisassembleOnActivateSystem.cs @@ -33,7 +33,7 @@ namespace Content.Server.Engineering.EntitySystems BreakOnUserMove = true, BreakOnStun = true, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) return; diff --git a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs index 1ccb603416..ef71b16e43 100644 --- a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs +++ b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs @@ -50,7 +50,7 @@ namespace Content.Server.Engineering.EntitySystems BreakOnStun = true, PostCheck = IsTileClear, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) return; diff --git a/Content.Server/Fluids/Components/BucketComponent.cs b/Content.Server/Fluids/Components/BucketComponent.cs index a205e507e3..2774549cb8 100644 --- a/Content.Server/Fluids/Components/BucketComponent.cs +++ b/Content.Server/Fluids/Components/BucketComponent.cs @@ -82,7 +82,7 @@ namespace Content.Server.Fluids.Components BreakOnStun = true, BreakOnDamage = true, }; - var result = await EntitySystem.Get().DoAfter(doAfterArgs); + var result = await EntitySystem.Get().WaitDoAfter(doAfterArgs); _currentlyUsing.Remove(eventArgs.Using.Uid); diff --git a/Content.Server/Fluids/Components/MopComponent.cs b/Content.Server/Fluids/Components/MopComponent.cs index 864358d321..fa0c7ec11e 100644 --- a/Content.Server/Fluids/Components/MopComponent.cs +++ b/Content.Server/Fluids/Components/MopComponent.cs @@ -123,7 +123,7 @@ namespace Content.Server.Fluids.Components BreakOnStun = true, BreakOnDamage = true, }; - var result = await EntitySystem.Get().DoAfter(doAfterArgs); + var result = await EntitySystem.Get().WaitDoAfter(doAfterArgs); Mopping = false; diff --git a/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs b/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs index 4403a12c4f..8e5c27d0fd 100644 --- a/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs +++ b/Content.Server/Kitchen/Components/KitchenSpikeComponent.cs @@ -133,7 +133,7 @@ namespace Content.Server.Kitchen.Components _beingButchered.Add(victimUid); - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); _beingButchered.Remove(victimUid); diff --git a/Content.Server/RCD/Components/RCDComponent.cs b/Content.Server/RCD/Components/RCDComponent.cs index aa344649b8..1f6f229023 100644 --- a/Content.Server/RCD/Components/RCDComponent.cs +++ b/Content.Server/RCD/Components/RCDComponent.cs @@ -119,7 +119,7 @@ namespace Content.Server.RCD.Components ExtraCheck = () => IsRCDStillValid(eventArgs, mapGrid, tile, snapPos, startingMode) //All of the sanity checks are here }; - var result = await _doAfterSystem.DoAfter(doAfterEventArgs); + var result = await _doAfterSystem.WaitDoAfter(doAfterEventArgs); if (result == DoAfterStatus.Cancelled) { return true; diff --git a/Content.Server/Storage/Components/ServerStorageComponent.cs b/Content.Server/Storage/Components/ServerStorageComponent.cs index 459f0d14e7..41def850b7 100644 --- a/Content.Server/Storage/Components/ServerStorageComponent.cs +++ b/Content.Server/Storage/Components/ServerStorageComponent.cs @@ -522,7 +522,7 @@ namespace Content.Server.Storage.Components BreakOnUserMove = true, NeedHand = true, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) return true; } diff --git a/Content.Server/Strip/StrippableComponent.cs b/Content.Server/Strip/StrippableComponent.cs index 05a4927e41..240d0cd0fd 100644 --- a/Content.Server/Strip/StrippableComponent.cs +++ b/Content.Server/Strip/StrippableComponent.cs @@ -197,7 +197,7 @@ namespace Content.Server.Strip NeedHand = true, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) return; userHands.Drop(item!.Owner, false); @@ -264,7 +264,7 @@ namespace Content.Server.Strip NeedHand = true, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) return; userHands.Drop(hand); @@ -314,7 +314,7 @@ namespace Content.Server.Strip BreakOnUserMove = true, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) return; var item = inventory.GetSlotItem(slot); @@ -370,7 +370,7 @@ namespace Content.Server.Strip BreakOnUserMove = true, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) return; var item = hands.GetItem(hand); diff --git a/Content.Server/Tools/Components/ToolComponent.cs b/Content.Server/Tools/Components/ToolComponent.cs index 63e1345328..8eff4dd539 100644 --- a/Content.Server/Tools/Components/ToolComponent.cs +++ b/Content.Server/Tools/Components/ToolComponent.cs @@ -85,7 +85,7 @@ namespace Content.Server.Tools.Components NeedHand = true, }; - var result = await doAfterSystem.DoAfter(doAfterArgs); + var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result == DoAfterStatus.Cancelled) return false;