DoAfter Refactor Fixes (#14278)

* Doafterfixes

* Injector blocker
This commit is contained in:
keronshb
2023-02-26 00:33:06 -05:00
committed by GitHub
parent 0d6f64e6d0
commit ec739c24da
13 changed files with 148 additions and 54 deletions

View File

@@ -18,7 +18,7 @@ public sealed class BotanySwabSystem : EntitySystem
base.Initialize(); base.Initialize();
SubscribeLocalEvent<BotanySwabComponent, ExaminedEvent>(OnExamined); SubscribeLocalEvent<BotanySwabComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<BotanySwabComponent, AfterInteractEvent>(OnAfterInteract); SubscribeLocalEvent<BotanySwabComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<DoAfterEvent>(OnDoAfter); SubscribeLocalEvent<BotanySwabComponent, DoAfterEvent>(OnDoAfter);
} }
/// <summary> /// <summary>
@@ -41,7 +41,7 @@ public sealed class BotanySwabSystem : EntitySystem
/// </summary> /// </summary>
private void OnAfterInteract(EntityUid uid, BotanySwabComponent swab, AfterInteractEvent args) private void OnAfterInteract(EntityUid uid, BotanySwabComponent swab, AfterInteractEvent args)
{ {
if (args.Target == null || !args.CanReach) if (args.Target == null || !args.CanReach || !HasComp<PlantHolderComponent>(args.Target))
return; return;
_doAfterSystem.DoAfter(new DoAfterEventArgs(args.User, swab.SwabDelay, target: args.Target, used: uid) _doAfterSystem.DoAfter(new DoAfterEventArgs(args.User, swab.SwabDelay, target: args.Target, used: uid)
@@ -57,7 +57,7 @@ public sealed class BotanySwabSystem : EntitySystem
/// <summary> /// <summary>
/// Save seed data or cross-pollenate. /// Save seed data or cross-pollenate.
/// </summary> /// </summary>
private void OnDoAfter(DoAfterEvent args) private void OnDoAfter(EntityUid uid, BotanySwabComponent component, DoAfterEvent args)
{ {
if (args.Cancelled || args.Handled || !TryComp<PlantHolderComponent>(args.Args.Target, out var plant) || !TryComp<BotanySwabComponent>(args.Args.Used, out var swab)) if (args.Cancelled || args.Handled || !TryComp<PlantHolderComponent>(args.Args.Target, out var plant) || !TryComp<BotanySwabComponent>(args.Args.Used, out var swab))
return; return;

View File

@@ -129,11 +129,18 @@ public sealed partial class ChemistrySystem
private void OnInjectDoAfter(EntityUid uid, InjectorComponent component, DoAfterEvent args) private void OnInjectDoAfter(EntityUid uid, InjectorComponent component, DoAfterEvent args)
{ {
if (args.Handled || args.Cancelled || args.Args.Target == null) if (args.Cancelled)
{
component.IsInjecting = false;
return;
}
if (args.Handled || args.Args.Target == null)
return; return;
UseInjector(args.Args.Target.Value, args.Args.User, uid, component); UseInjector(args.Args.Target.Value, args.Args.User, uid, component);
component.IsInjecting = false;
args.Handled = true; args.Handled = true;
} }
@@ -216,12 +223,18 @@ public sealed partial class ChemistrySystem
if (!_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution)) if (!_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution))
return; return;
//If it found it's injecting
if (component.IsInjecting)
return;
var actualDelay = MathF.Max(component.Delay, 1f); var actualDelay = MathF.Max(component.Delay, 1f);
// Injections take 1 second longer per additional 5u // Injections take 1 second longer per additional 5u
actualDelay += (float) component.TransferAmount / component.Delay - 1; actualDelay += (float) component.TransferAmount / component.Delay - 1;
if (user != target) var isTarget = user != target;
if (isTarget)
{ {
// Create a pop-up for the target // Create a pop-up for the target
var userName = Identity.Entity(user, EntityManager); var userName = Identity.Entity(user, EntityManager);
@@ -256,8 +269,12 @@ public sealed partial class ChemistrySystem
_adminLogger.Add(LogType.Ingestion, $"{EntityManager.ToPrettyString(user):user} is attempting to inject themselves with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}."); _adminLogger.Add(LogType.Ingestion, $"{EntityManager.ToPrettyString(user):user} is attempting to inject themselves with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}.");
} }
component.IsInjecting = true;
_doAfter.DoAfter(new DoAfterEventArgs(user, actualDelay, target:target, used:injector) _doAfter.DoAfter(new DoAfterEventArgs(user, actualDelay, target:target, used:injector)
{ {
RaiseOnTarget = isTarget,
RaiseOnUser = !isTarget,
BreakOnUserMove = true, BreakOnUserMove = true,
BreakOnDamage = true, BreakOnDamage = true,
BreakOnStun = true, BreakOnStun = true,

View File

@@ -47,7 +47,7 @@ namespace Content.Server.Disease
// Private Events // Private Events
SubscribeLocalEvent<DiseaseDiagnoserComponent, DiseaseMachineFinishedEvent>(OnDiagnoserFinished); SubscribeLocalEvent<DiseaseDiagnoserComponent, DiseaseMachineFinishedEvent>(OnDiagnoserFinished);
SubscribeLocalEvent<DiseaseVaccineCreatorComponent, DiseaseMachineFinishedEvent>(OnVaccinatorFinished); SubscribeLocalEvent<DiseaseVaccineCreatorComponent, DiseaseMachineFinishedEvent>(OnVaccinatorFinished);
SubscribeLocalEvent<DoAfterEvent>(OnSwabDoAfter); SubscribeLocalEvent<DiseaseSwabComponent, DoAfterEvent>(OnSwabDoAfter);
} }
private Queue<EntityUid> AddQueue = new(); private Queue<EntityUid> AddQueue = new();
@@ -99,7 +99,7 @@ namespace Content.Server.Disease
/// </summary> /// </summary>
private void OnAfterInteract(EntityUid uid, DiseaseSwabComponent swab, AfterInteractEvent args) private void OnAfterInteract(EntityUid uid, DiseaseSwabComponent swab, AfterInteractEvent args)
{ {
if (args.Target == null || !args.CanReach) if (args.Target == null || !args.CanReach || !HasComp<DiseaseCarrierComponent>(args.Target))
return; return;
if (swab.Used) if (swab.Used)
@@ -116,8 +116,12 @@ namespace Content.Server.Disease
return; return;
} }
var isTarget = args.User != args.Target;
_doAfterSystem.DoAfter(new DoAfterEventArgs(args.User, swab.SwabDelay, target: args.Target, used: uid) _doAfterSystem.DoAfter(new DoAfterEventArgs(args.User, swab.SwabDelay, target: args.Target, used: uid)
{ {
RaiseOnTarget = isTarget,
RaiseOnUser = !isTarget,
BreakOnTargetMove = true, BreakOnTargetMove = true,
BreakOnUserMove = true, BreakOnUserMove = true,
BreakOnStun = true, BreakOnStun = true,
@@ -301,9 +305,9 @@ namespace Content.Server.Disease
/// Copies a disease prototype to the swab /// Copies a disease prototype to the swab
/// after the doafter completes. /// after the doafter completes.
/// </summary> /// </summary>
private void OnSwabDoAfter(DoAfterEvent args) private void OnSwabDoAfter(EntityUid uid, DiseaseSwabComponent component, DoAfterEvent args)
{ {
if (args.Handled || args.Cancelled || !TryComp<DiseaseCarrierComponent>(args.Args.Target, out var carrier) || !TryComp<DiseaseSwabComponent>(args.Args.Target, out var swab)) if (args.Handled || args.Cancelled || !TryComp<DiseaseCarrierComponent>(args.Args.Target, out var carrier) || !TryComp<DiseaseSwabComponent>(args.Args.Used, out var swab))
return; return;
swab.Used = true; swab.Used = true;
@@ -313,7 +317,6 @@ namespace Content.Server.Disease
return; return;
swab.Disease = _random.Pick(carrier.Diseases); swab.Disease = _random.Pick(carrier.Diseases);
} }

View File

@@ -39,6 +39,12 @@ namespace Content.Server.Medical.Components
[DataField("delay")] [DataField("delay")]
public float Delay = 3f; public float Delay = 3f;
/// <summary>
/// Cancel token to prevent rapid healing
/// </summary>
[DataField("cancelToken")]
public CancellationTokenSource? CancelToken;
/// <summary> /// <summary>
/// Delay multiplier when healing yourself. /// Delay multiplier when healing yourself.
/// </summary> /// </summary>

View File

@@ -1,3 +1,4 @@
using System.Threading;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Body.Systems; using Content.Server.Body.Systems;
using Content.Server.DoAfter; using Content.Server.DoAfter;
@@ -40,6 +41,12 @@ public sealed class HealingSystem : EntitySystem
private void OnDoAfter(EntityUid uid, DamageableComponent component, DoAfterEvent<HealingData> args) private void OnDoAfter(EntityUid uid, DamageableComponent component, DoAfterEvent<HealingData> args)
{ {
if (args.Cancelled)
{
args.AdditionalData.HealingComponent.CancelToken = null;
return;
}
if (args.Handled || args.Cancelled || _mobStateSystem.IsDead(uid) || args.Args.Used == null) if (args.Handled || args.Cancelled || _mobStateSystem.IsDead(uid) || args.Args.Used == null)
return; return;
@@ -67,6 +74,7 @@ public sealed class HealingSystem : EntitySystem
if (args.AdditionalData.HealingComponent.HealingEndSound != null) if (args.AdditionalData.HealingComponent.HealingEndSound != null)
_audio.PlayPvs(args.AdditionalData.HealingComponent.HealingEndSound, uid, AudioHelpers.WithVariation(0.125f, _random).WithVolume(-5f)); _audio.PlayPvs(args.AdditionalData.HealingComponent.HealingEndSound, uid, AudioHelpers.WithVariation(0.125f, _random).WithVolume(-5f));
args.AdditionalData.HealingComponent.CancelToken = null;
args.Handled = true; args.Handled = true;
} }
@@ -90,7 +98,7 @@ public sealed class HealingSystem : EntitySystem
private bool TryHeal(EntityUid uid, EntityUid user, EntityUid target, HealingComponent component) private bool TryHeal(EntityUid uid, EntityUid user, EntityUid target, HealingComponent component)
{ {
if (_mobStateSystem.IsDead(target) || !TryComp<DamageableComponent>(target, out var targetDamage)) if (_mobStateSystem.IsDead(target) || !TryComp<DamageableComponent>(target, out var targetDamage) || component.CancelToken != null)
return false; return false;
if (targetDamage.TotalDamage == 0) if (targetDamage.TotalDamage == 0)
@@ -108,14 +116,21 @@ public sealed class HealingSystem : EntitySystem
if (component.HealingBeginSound != null) if (component.HealingBeginSound != null)
_audio.PlayPvs(component.HealingBeginSound, uid, AudioHelpers.WithVariation(0.125f, _random).WithVolume(-5f)); _audio.PlayPvs(component.HealingBeginSound, uid, AudioHelpers.WithVariation(0.125f, _random).WithVolume(-5f));
var delay = user != target var isNotSelf = user != target;
var delay = isNotSelf
? component.Delay ? component.Delay
: component.Delay * GetScaledHealingPenalty(user, component); : component.Delay * GetScaledHealingPenalty(user, component);
component.CancelToken = new CancellationTokenSource();
var healingData = new HealingData(component, stack); var healingData = new HealingData(component, stack);
var doAfterEventArgs = new DoAfterEventArgs(user, delay, target: target, used: uid) var doAfterEventArgs = new DoAfterEventArgs(user, delay, cancelToken: component.CancelToken.Token,target: target, used: uid)
{ {
//Raise the event on the target if it's not self, otherwise raise it on self.
RaiseOnTarget = isNotSelf,
RaiseOnUser = !isNotSelf,
BreakOnUserMove = true, BreakOnUserMove = true,
BreakOnTargetMove = true, BreakOnTargetMove = true,
// Didn't break on damage as they may be trying to prevent it and // Didn't break on damage as they may be trying to prevent it and

View File

@@ -34,6 +34,13 @@ namespace Content.Server.Nutrition.Components
[DataField("burstSound")] [DataField("burstSound")]
public SoundSpecifier BurstSound = new SoundPathSpecifier("/Audio/Effects/flash_bang.ogg"); public SoundSpecifier BurstSound = new SoundPathSpecifier("/Audio/Effects/flash_bang.ogg");
/// <summary>
/// Is this drink being forced on someone else?
/// </summary>
/// <returns></returns>
[DataField("forceDrink")]
public bool ForceDrink;
/// <summary> /// <summary>
/// How long it takes to drink this yourself. /// How long it takes to drink this yourself.
/// </summary> /// </summary>

View File

@@ -40,6 +40,13 @@ namespace Content.Server.Nutrition.Components
[DataField("eatMessage")] [DataField("eatMessage")]
public string EatMessage = "food-nom"; public string EatMessage = "food-nom";
/// <summary>
/// Is this entity being forcefed?
/// Prevents the entity from being forced to eat multiple times if not self
/// </summary>
[DataField("forceFeed")]
public bool ForceFeed;
/// <summary> /// <summary>
/// How long it takes to eat the food personally. /// How long it takes to eat the food personally.
/// </summary> /// </summary>

View File

@@ -217,7 +217,7 @@ namespace Content.Server.Nutrition.EntitySystems
private bool TryDrink(EntityUid user, EntityUid target, DrinkComponent drink, EntityUid item) private bool TryDrink(EntityUid user, EntityUid target, DrinkComponent drink, EntityUid item)
{ {
if (!EntityManager.HasComponent<BodyComponent>(target)) if (!EntityManager.HasComponent<BodyComponent>(target) || drink.ForceDrink)
return false; return false;
if (!drink.Opened) if (!drink.Opened)
@@ -241,9 +241,9 @@ namespace Content.Server.Nutrition.EntitySystems
if (!_interactionSystem.InRangeUnobstructed(user, item, popup: true)) if (!_interactionSystem.InRangeUnobstructed(user, item, popup: true))
return true; return true;
var forceDrink = user != target; drink.ForceDrink = user != target;
if (forceDrink) if (drink.ForceDrink)
{ {
var userName = Identity.Entity(user, EntityManager); var userName = Identity.Entity(user, EntityManager);
@@ -264,7 +264,7 @@ namespace Content.Server.Nutrition.EntitySystems
var drinkData = new DrinkData(drinkSolution, flavors); var drinkData = new DrinkData(drinkSolution, flavors);
var doAfterEventArgs = new DoAfterEventArgs(user, forceDrink ? drink.ForceFeedDelay : drink.Delay, var doAfterEventArgs = new DoAfterEventArgs(user, drink.ForceDrink ? drink.ForceFeedDelay : drink.Delay,
target: target, used: item) target: target, used: item)
{ {
BreakOnUserMove = moveBreak, BreakOnUserMove = moveBreak,
@@ -286,6 +286,14 @@ namespace Content.Server.Nutrition.EntitySystems
/// </summary> /// </summary>
private void OnDoAfter(EntityUid uid, DrinkComponent component, DoAfterEvent<DrinkData> args) private void OnDoAfter(EntityUid uid, DrinkComponent component, DoAfterEvent<DrinkData> args)
{ {
//Special cancel if they're force feeding someone.
//Allows self to drink multiple times but prevents force feeding drinks to others rapidly.
if (args.Cancelled && component.ForceDrink)
{
component.ForceDrink = false;
return;
}
if (args.Handled || args.Cancelled || component.Deleted) if (args.Handled || args.Cancelled || component.Deleted)
return; return;
@@ -295,11 +303,11 @@ namespace Content.Server.Nutrition.EntitySystems
var transferAmount = FixedPoint2.Min(component.TransferAmount, args.AdditionalData.DrinkSolution.Volume); var transferAmount = FixedPoint2.Min(component.TransferAmount, args.AdditionalData.DrinkSolution.Volume);
var drained = _solutionContainerSystem.Drain(uid, args.AdditionalData.DrinkSolution, transferAmount); var drained = _solutionContainerSystem.Drain(uid, args.AdditionalData.DrinkSolution, transferAmount);
var forceDrink = args.Args.Target.Value != args.Args.User; //var forceDrink = args.Args.Target.Value != args.Args.User;
if (!_bodySystem.TryGetBodyOrganComponents<StomachComponent>(args.Args.Target.Value, out var stomachs, body)) if (!_bodySystem.TryGetBodyOrganComponents<StomachComponent>(args.Args.Target.Value, out var stomachs, body))
{ {
_popupSystem.PopupEntity(forceDrink ? Loc.GetString("drink-component-try-use-drink-cannot-drink-other") : Loc.GetString("drink-component-try-use-drink-had-enough"), args.Args.Target.Value, args.Args.User); _popupSystem.PopupEntity(component.ForceDrink ? Loc.GetString("drink-component-try-use-drink-cannot-drink-other") : Loc.GetString("drink-component-try-use-drink-had-enough"), args.Args.Target.Value, args.Args.User);
if (HasComp<RefillableSolutionComponent>(args.Args.Target.Value)) if (HasComp<RefillableSolutionComponent>(args.Args.Target.Value))
{ {
@@ -320,7 +328,7 @@ namespace Content.Server.Nutrition.EntitySystems
{ {
_popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-had-enough"), args.Args.Target.Value, args.Args.Target.Value); _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-had-enough"), args.Args.Target.Value, args.Args.Target.Value);
if (forceDrink) if (component.ForceDrink)
{ {
_popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-had-enough-other"), args.Args.Target.Value, args.Args.User); _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-had-enough-other"), args.Args.Target.Value, args.Args.User);
_spillableSystem.SpillAt(args.Args.Target.Value, drained, "PuddleSmear"); _spillableSystem.SpillAt(args.Args.Target.Value, drained, "PuddleSmear");
@@ -334,7 +342,7 @@ namespace Content.Server.Nutrition.EntitySystems
var flavors = args.AdditionalData.FlavorMessage; var flavors = args.AdditionalData.FlavorMessage;
if (forceDrink) if (component.ForceDrink)
{ {
var targetName = Identity.Entity(args.Args.Target.Value, EntityManager); var targetName = Identity.Entity(args.Args.Target.Value, EntityManager);
var userName = Identity.Entity(args.Args.User, EntityManager); var userName = Identity.Entity(args.Args.User, EntityManager);
@@ -366,6 +374,7 @@ namespace Content.Server.Nutrition.EntitySystems
//TODO: Grab the stomach UIDs somehow without using Owner //TODO: Grab the stomach UIDs somehow without using Owner
_stomachSystem.TryTransferSolution(firstStomach.Value.Comp.Owner, drained, firstStomach.Value.Comp); _stomachSystem.TryTransferSolution(firstStomach.Value.Comp.Owner, drained, firstStomach.Value.Comp);
component.ForceDrink = false;
args.Handled = true; args.Handled = true;
} }

View File

@@ -86,8 +86,8 @@ namespace Content.Server.Nutrition.EntitySystems
if (food == user || EntityManager.TryGetComponent<MobStateComponent>(food, out var mobState) && _mobStateSystem.IsAlive(food, mobState)) // Suppresses eating alive mobs if (food == user || EntityManager.TryGetComponent<MobStateComponent>(food, out var mobState) && _mobStateSystem.IsAlive(food, mobState)) // Suppresses eating alive mobs
return false; return false;
// Target can't be fed // Target can't be fed or they're already forcefeeding
if (!EntityManager.HasComponent<BodyComponent>(target)) if (!EntityManager.HasComponent<BodyComponent>(target) || foodComp.ForceFeed)
return false; return false;
if (!_solutionContainerSystem.TryGetSolution(food, foodComp.SolutionName, out var foodSolution)) if (!_solutionContainerSystem.TryGetSolution(food, foodComp.SolutionName, out var foodSolution))
@@ -111,9 +111,9 @@ namespace Content.Server.Nutrition.EntitySystems
if (!_interactionSystem.InRangeUnobstructed(user, food, popup: true)) if (!_interactionSystem.InRangeUnobstructed(user, food, popup: true))
return true; return true;
var forceFeed = user != target; foodComp.ForceFeed = user != target;
if (forceFeed) if (foodComp.ForceFeed)
{ {
var userName = Identity.Entity(user, EntityManager); var userName = Identity.Entity(user, EntityManager);
_popupSystem.PopupEntity(Loc.GetString("food-system-force-feed", ("user", userName)), _popupSystem.PopupEntity(Loc.GetString("food-system-force-feed", ("user", userName)),
@@ -128,16 +128,16 @@ namespace Content.Server.Nutrition.EntitySystems
_adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(target):target} is eating {ToPrettyString(food):food} {SolutionContainerSystem.ToPrettyString(foodSolution)}"); _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(target):target} is eating {ToPrettyString(food):food} {SolutionContainerSystem.ToPrettyString(foodSolution)}");
} }
var moveBreak = user != target;
var foodData = new FoodData(foodSolution, flavors, utensils); var foodData = new FoodData(foodSolution, flavors, utensils);
var doAfterEventArgs = new DoAfterEventArgs(user, forceFeed ? foodComp.ForceFeedDelay : foodComp.Delay, target: target, used: food) var doAfterEventArgs = new DoAfterEventArgs(user, foodComp.ForceFeed ? foodComp.ForceFeedDelay : foodComp.Delay, target: target, used: food)
{ {
BreakOnUserMove = moveBreak, RaiseOnTarget = foodComp.ForceFeed,
RaiseOnUser = !foodComp.ForceFeed,
BreakOnUserMove = foodComp.ForceFeed,
BreakOnDamage = true, BreakOnDamage = true,
BreakOnStun = true, BreakOnStun = true,
BreakOnTargetMove = moveBreak, BreakOnTargetMove = foodComp.ForceFeed,
MovementThreshold = 0.01f, MovementThreshold = 0.01f,
DistanceThreshold = 1.0f, DistanceThreshold = 1.0f,
NeedHand = true NeedHand = true
@@ -151,6 +151,13 @@ namespace Content.Server.Nutrition.EntitySystems
private void OnDoAfter(EntityUid uid, FoodComponent component, DoAfterEvent<FoodData> args) private void OnDoAfter(EntityUid uid, FoodComponent component, DoAfterEvent<FoodData> args)
{ {
//Prevents the target from being force fed food but allows the user to chow down
if (args.Cancelled && component.ForceFeed)
{
component.ForceFeed = false;
return;
}
if (args.Cancelled || args.Handled || component.Deleted || args.Args.Target == null) if (args.Cancelled || args.Handled || component.Deleted || args.Args.Target == null)
return; return;
@@ -166,13 +173,11 @@ namespace Content.Server.Nutrition.EntitySystems
//TODO: Get the stomach UID somehow without nabbing owner //TODO: Get the stomach UID somehow without nabbing owner
var firstStomach = stomachs.FirstOrNull(stomach => _stomachSystem.CanTransferSolution(stomach.Comp.Owner, split)); var firstStomach = stomachs.FirstOrNull(stomach => _stomachSystem.CanTransferSolution(stomach.Comp.Owner, split));
var forceFeed = args.Args.Target.Value != args.Args.User;
// No stomach so just popup a message that they can't eat. // No stomach so just popup a message that they can't eat.
if (firstStomach == null) if (firstStomach == null)
{ {
_solutionContainerSystem.TryAddSolution(uid, args.AdditionalData.FoodSolution, split); _solutionContainerSystem.TryAddSolution(uid, args.AdditionalData.FoodSolution, split);
_popupSystem.PopupEntity(forceFeed ? Loc.GetString("food-system-you-cannot-eat-any-more-other") : Loc.GetString("food-system-you-cannot-eat-any-more"), args.Args.Target.Value, args.Args.User); _popupSystem.PopupEntity(component.ForceFeed ? Loc.GetString("food-system-you-cannot-eat-any-more-other") : Loc.GetString("food-system-you-cannot-eat-any-more"), args.Args.Target.Value, args.Args.User);
args.Handled = true; args.Handled = true;
return; return;
} }
@@ -182,7 +187,7 @@ namespace Content.Server.Nutrition.EntitySystems
var flavors = args.AdditionalData.FlavorMessage; var flavors = args.AdditionalData.FlavorMessage;
if (forceFeed) if (component.ForceFeed)
{ {
var targetName = Identity.Entity(args.Args.Target.Value, EntityManager); var targetName = Identity.Entity(args.Args.Target.Value, EntityManager);
var userName = Identity.Entity(args.Args.User, EntityManager); var userName = Identity.Entity(args.Args.User, EntityManager);

View File

@@ -15,5 +15,8 @@ namespace Content.Server.Tools.Components
[DataField("delay")] [DataField("delay")]
public float Delay = 1f; public float Delay = 1f;
[DataField("cancelToken")]
public CancellationTokenSource? CancelToken;
} }
} }

View File

@@ -19,10 +19,20 @@ public sealed partial class ToolSystem
{ {
SubscribeLocalEvent<TilePryingComponent, AfterInteractEvent>(OnTilePryingAfterInteract); SubscribeLocalEvent<TilePryingComponent, AfterInteractEvent>(OnTilePryingAfterInteract);
SubscribeLocalEvent<TilePryingComponent, TilePryingCompleteEvent>(OnTilePryComplete); SubscribeLocalEvent<TilePryingComponent, TilePryingCompleteEvent>(OnTilePryComplete);
SubscribeLocalEvent<TilePryingComponent, TilePryingCancelledEvent>(OnTilePryCancelled);
}
private void OnTilePryingAfterInteract(EntityUid uid, TilePryingComponent component, AfterInteractEvent args)
{
if (args.Handled || !args.CanReach || (args.Target != null && !HasComp<PuddleComponent>(args.Target))) return;
if (TryPryTile(uid, args.User, component, args.ClickLocation))
args.Handled = true;
} }
private void OnTilePryComplete(EntityUid uid, TilePryingComponent component, TilePryingCompleteEvent args) private void OnTilePryComplete(EntityUid uid, TilePryingComponent component, TilePryingCompleteEvent args)
{ {
component.CancelToken = null;
var gridUid = args.Coordinates.GetGridUid(EntityManager); var gridUid = args.Coordinates.GetGridUid(EntityManager);
if (!_mapManager.TryGetGrid(gridUid, out var grid)) if (!_mapManager.TryGetGrid(gridUid, out var grid))
{ {
@@ -34,17 +44,14 @@ public sealed partial class ToolSystem
_tile.PryTile(tile); _tile.PryTile(tile);
} }
private void OnTilePryingAfterInteract(EntityUid uid, TilePryingComponent component, AfterInteractEvent args) private void OnTilePryCancelled(EntityUid uid, TilePryingComponent component, TilePryingCancelledEvent args)
{ {
if (args.Handled || !args.CanReach || (args.Target != null && !HasComp<PuddleComponent>(args.Target))) return; component.CancelToken = null;
if (TryPryTile(uid, args.User, component, args.ClickLocation))
args.Handled = true;
} }
private bool TryPryTile(EntityUid toolEntity, EntityUid user, TilePryingComponent component, EntityCoordinates clickLocation) private bool TryPryTile(EntityUid toolEntity, EntityUid user, TilePryingComponent component, EntityCoordinates clickLocation)
{ {
if (!TryComp<ToolComponent?>(toolEntity, out var tool) && component.ToolComponentNeeded) if (!TryComp<ToolComponent?>(toolEntity, out var tool) && component.ToolComponentNeeded || component.CancelToken != null)
return false; return false;
if (!_mapManager.TryGetGrid(clickLocation.GetGridUid(EntityManager), out var mapGrid)) if (!_mapManager.TryGetGrid(clickLocation.GetGridUid(EntityManager), out var mapGrid))
@@ -62,9 +69,11 @@ public sealed partial class ToolSystem
if (!tileDef.CanCrowbar) if (!tileDef.CanCrowbar)
return false; return false;
var toolEvData = new ToolEventData(new TilePryingCompleteEvent(clickLocation), targetEntity:toolEntity); component.CancelToken = new CancellationTokenSource();
if (!UseTool(toolEntity, user, null, component.Delay, new[] { component.QualityNeeded }, toolEvData, toolComponent: tool)) var toolEvData = new ToolEventData(new TilePryingCompleteEvent(clickLocation), cancelledEv:new TilePryingCancelledEvent() ,targetEntity:toolEntity);
if (!UseTool(toolEntity, user, null, component.Delay, new[] { component.QualityNeeded }, toolEvData, toolComponent: tool, cancelToken: component.CancelToken))
return false; return false;
return true; return true;

View File

@@ -10,6 +10,12 @@ namespace Content.Shared.Chemistry.Components
[NetworkedComponent, ComponentProtoName("Injector")] [NetworkedComponent, ComponentProtoName("Injector")]
public abstract class SharedInjectorComponent : Component public abstract class SharedInjectorComponent : Component
{ {
/// <summary>
/// Checks to see if the entity being injected
/// </summary>
[DataField("isInjecting")]
public bool IsInjecting;
/// <summary> /// <summary>
/// Component data used for net updates. Used by client for item status ui /// Component data used for net updates. Used by client for item status ui
/// </summary> /// </summary>

View File

@@ -1,4 +1,5 @@
using System.Linq; using System.Linq;
using System.Threading;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.DoAfter; using Content.Shared.DoAfter;
using Content.Shared.Interaction; using Content.Shared.Interaction;
@@ -31,9 +32,24 @@ public abstract class SharedToolSystem : EntitySystem
private void OnDoAfter(EntityUid uid, ToolComponent component, DoAfterEvent<ToolEventData> args) private void OnDoAfter(EntityUid uid, ToolComponent component, DoAfterEvent<ToolEventData> args)
{ {
if (args.Handled || args.Cancelled || args.AdditionalData.Ev == null) if (args.Handled || args.AdditionalData.Ev == null)
return; return;
if (args.Cancelled)
{
if (args.AdditionalData.CancelledEv != null)
{
if (args.AdditionalData.TargetEntity != null)
RaiseLocalEvent(args.AdditionalData.TargetEntity.Value, args.AdditionalData.CancelledEv);
else
RaiseLocalEvent(args.AdditionalData.CancelledEv);
args.Handled = true;
}
return;
}
if (ToolFinishUse(uid, args.Args.User, args.AdditionalData.Fuel)) if (ToolFinishUse(uid, args.Args.User, args.AdditionalData.Fuel))
{ {
if (args.AdditionalData.TargetEntity != null) if (args.AdditionalData.TargetEntity != null)
@@ -43,18 +59,9 @@ public abstract class SharedToolSystem : EntitySystem
args.Handled = true; args.Handled = true;
} }
else if (args.AdditionalData.CancelledEv != null)
{
if (args.AdditionalData.TargetEntity != null)
RaiseLocalEvent(args.AdditionalData.TargetEntity.Value, args.AdditionalData.CancelledEv);
else
RaiseLocalEvent(args.AdditionalData.CancelledEv);
args.Handled = true;
}
} }
public bool UseTool(EntityUid tool, EntityUid user, EntityUid? target, float doAfterDelay, IEnumerable<string> toolQualitiesNeeded, ToolEventData toolEventData, float fuel = 0f, ToolComponent? toolComponent = null, Func<bool>? doAfterCheck = null) public bool UseTool(EntityUid tool, EntityUid user, EntityUid? target, float doAfterDelay, IEnumerable<string> toolQualitiesNeeded, ToolEventData toolEventData, float fuel = 0f, ToolComponent? toolComponent = null, Func<bool>? doAfterCheck = null, CancellationTokenSource? cancelToken = null)
{ {
// No logging here, after all that'd mean the caller would need to check if the component is there or not. // No logging here, after all that'd mean the caller would need to check if the component is there or not.
if (!Resolve(tool, ref toolComponent, false)) if (!Resolve(tool, ref toolComponent, false))
@@ -70,7 +77,7 @@ public abstract class SharedToolSystem : EntitySystem
if (doAfterDelay > 0f) if (doAfterDelay > 0f)
{ {
var doAfterArgs = new DoAfterEventArgs(user, doAfterDelay / toolComponent.SpeedModifier, target:target, used:tool) var doAfterArgs = new DoAfterEventArgs(user, doAfterDelay / toolComponent.SpeedModifier, cancelToken:cancelToken?.Token ?? default, target:target, used:tool)
{ {
ExtraCheck = doAfterCheck, ExtraCheck = doAfterCheck,
BreakOnDamage = true, BreakOnDamage = true,