Fix food & do-after bugs (#5716)
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
@@ -64,9 +65,10 @@ namespace Content.Server.Chemistry.Components
|
|||||||
public float Delay = 5;
|
public float Delay = 5;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is this component currently being used in a DoAfter?
|
/// Token for interrupting a do-after action (e.g., injection another player). If not null, implies
|
||||||
|
/// component is currently "in use".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool InUse = false;
|
public CancellationTokenSource? CancelToken;
|
||||||
|
|
||||||
private InjectorToggleMode _toggleState;
|
private InjectorToggleMode _toggleState;
|
||||||
|
|
||||||
@@ -127,8 +129,11 @@ namespace Content.Server.Chemistry.Components
|
|||||||
/// <param name="eventArgs"></param>
|
/// <param name="eventArgs"></param>
|
||||||
async Task<bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
|
async Task<bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (InUse)
|
if (CancelToken != null)
|
||||||
return false;
|
{
|
||||||
|
CancelToken.Cancel();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true))
|
if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true))
|
||||||
return false;
|
return false;
|
||||||
@@ -197,7 +202,6 @@ namespace Content.Server.Chemistry.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<bool> TryInjectDoAfter(EntityUid user, EntityUid target)
|
public async Task<bool> TryInjectDoAfter(EntityUid user, EntityUid target)
|
||||||
{
|
{
|
||||||
InUse = true;
|
|
||||||
var popupSys = EntitySystem.Get<SharedPopupSystem>();
|
var popupSys = EntitySystem.Get<SharedPopupSystem>();
|
||||||
|
|
||||||
// Create a pop-up for the user
|
// Create a pop-up for the user
|
||||||
@@ -249,8 +253,9 @@ namespace Content.Server.Chemistry.Components
|
|||||||
//TODO solution pretty string.
|
//TODO solution pretty string.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CancelToken = new();
|
||||||
var status = await EntitySystem.Get<DoAfterSystem>().WaitDoAfter(
|
var status = await EntitySystem.Get<DoAfterSystem>().WaitDoAfter(
|
||||||
new DoAfterEventArgs(user, actualDelay, target: target)
|
new DoAfterEventArgs(user, actualDelay, CancelToken.Token, target)
|
||||||
{
|
{
|
||||||
BreakOnUserMove = true,
|
BreakOnUserMove = true,
|
||||||
BreakOnDamage = true,
|
BreakOnDamage = true,
|
||||||
@@ -258,7 +263,7 @@ namespace Content.Server.Chemistry.Components
|
|||||||
BreakOnTargetMove = true,
|
BreakOnTargetMove = true,
|
||||||
MovementThreshold = 1.0f
|
MovementThreshold = 1.0f
|
||||||
});
|
});
|
||||||
InUse = false;
|
CancelToken = null;
|
||||||
|
|
||||||
return status == DoAfterStatus.Finished;
|
return status == DoAfterStatus.Finished;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Content.Server.Chemistry.Components;
|
using Content.Server.Chemistry.Components;
|
||||||
|
using Content.Shared.Hands;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.EntitySystems
|
namespace Content.Server.Chemistry.EntitySystems
|
||||||
{
|
{
|
||||||
@@ -12,6 +14,16 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<InjectorComponent, SolutionChangedEvent>(OnSolutionChange);
|
SubscribeLocalEvent<InjectorComponent, SolutionChangedEvent>(OnSolutionChange);
|
||||||
|
SubscribeLocalEvent<InjectorComponent, HandDeselectedEvent>(OnInjectorDeselected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInjectorDeselected(EntityUid uid, InjectorComponent component, HandDeselectedEvent args)
|
||||||
|
{
|
||||||
|
if (component.CancelToken != null)
|
||||||
|
{
|
||||||
|
component.CancelToken.Cancel();
|
||||||
|
component.CancelToken = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSolutionChange(EntityUid uid, InjectorComponent component, SolutionChangedEvent args)
|
private void OnSolutionChange(EntityUid uid, InjectorComponent component, SolutionChangedEvent args)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ namespace Content.Server.DoAfter
|
|||||||
public sealed class DoAfterSystem : EntitySystem
|
public sealed class DoAfterSystem : EntitySystem
|
||||||
{
|
{
|
||||||
// We cache these lists as to not allocate them every update tick...
|
// We cache these lists as to not allocate them every update tick...
|
||||||
private readonly List<DoAfter> _cancelled = new();
|
private readonly Queue<DoAfter> _cancelled = new();
|
||||||
private readonly List<DoAfter> _finished = new();
|
private readonly Queue<DoAfter> _finished = new();
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -52,17 +52,17 @@ namespace Content.Server.DoAfter
|
|||||||
case DoAfterStatus.Running:
|
case DoAfterStatus.Running:
|
||||||
break;
|
break;
|
||||||
case DoAfterStatus.Cancelled:
|
case DoAfterStatus.Cancelled:
|
||||||
_cancelled.Add(doAfter);
|
_cancelled.Enqueue(doAfter);
|
||||||
break;
|
break;
|
||||||
case DoAfterStatus.Finished:
|
case DoAfterStatus.Finished:
|
||||||
_finished.Add(doAfter);
|
_finished.Enqueue(doAfter);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var doAfter in _cancelled)
|
while (_cancelled.TryDequeue(out var doAfter))
|
||||||
{
|
{
|
||||||
comp.Cancelled(doAfter);
|
comp.Cancelled(doAfter);
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ namespace Content.Server.DoAfter
|
|||||||
RaiseLocalEvent(doAfter.EventArgs.BroadcastCancelledEvent);
|
RaiseLocalEvent(doAfter.EventArgs.BroadcastCancelledEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var doAfter in _finished)
|
while (_finished.TryDequeue(out var doAfter))
|
||||||
{
|
{
|
||||||
comp.Finished(doAfter);
|
comp.Finished(doAfter);
|
||||||
|
|
||||||
@@ -89,10 +89,6 @@ namespace Content.Server.DoAfter
|
|||||||
if(doAfter.EventArgs.BroadcastFinishedEvent != null)
|
if(doAfter.EventArgs.BroadcastFinishedEvent != null)
|
||||||
RaiseLocalEvent(doAfter.EventArgs.BroadcastFinishedEvent);
|
RaiseLocalEvent(doAfter.EventArgs.BroadcastFinishedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean the shared lists at the end, ensuring they'll be clean for the next time we need them.
|
|
||||||
_cancelled.Clear();
|
|
||||||
_finished.Clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Content.Shared.Chemistry.Reagent;
|
|
||||||
using Content.Shared.Sound;
|
using Content.Shared.Sound;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -7,6 +6,7 @@ using Robust.Shared.ViewVariables;
|
|||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Robust.Shared.Analyzers;
|
using Robust.Shared.Analyzers;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Content.Server.Nutrition.Components
|
namespace Content.Server.Nutrition.Components
|
||||||
{
|
{
|
||||||
@@ -50,8 +50,9 @@ namespace Content.Server.Nutrition.Components
|
|||||||
public float ForceFeedDelay = 3;
|
public float ForceFeedDelay = 3;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If true, this drink has some DoAfter active (someone is being force fed).
|
/// Token for interrupting a do-after action (e.g., force feeding). If not null, implies component is
|
||||||
|
/// currently "in use".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool InUse = false;
|
public CancellationTokenSource? CancelToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
@@ -55,9 +56,10 @@ namespace Content.Server.Nutrition.Components
|
|||||||
public float ForceFeedDelay = 3;
|
public float ForceFeedDelay = 3;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If true, this food has some DoAfter active (someone is being force fed).
|
/// Token for interrupting a do-after action (e.g., force feeding). If not null, implies component is
|
||||||
|
/// currently "in use".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool InUse = false;
|
public CancellationTokenSource? CancelToken;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public int UsesRemaining
|
public int UsesRemaining
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using Content.Shared.Chemistry.Reagent;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
@@ -54,12 +55,26 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
SubscribeLocalEvent<DrinkComponent, ComponentInit>(OnDrinkInit);
|
SubscribeLocalEvent<DrinkComponent, ComponentInit>(OnDrinkInit);
|
||||||
SubscribeLocalEvent<DrinkComponent, LandEvent>(HandleLand);
|
SubscribeLocalEvent<DrinkComponent, LandEvent>(HandleLand);
|
||||||
SubscribeLocalEvent<DrinkComponent, UseInHandEvent>(OnUse);
|
SubscribeLocalEvent<DrinkComponent, UseInHandEvent>(OnUse);
|
||||||
|
SubscribeLocalEvent<DrinkComponent, HandDeselectedEvent>(OnDrinkDeselected);
|
||||||
SubscribeLocalEvent<DrinkComponent, AfterInteractEvent>(AfterInteract);
|
SubscribeLocalEvent<DrinkComponent, AfterInteractEvent>(AfterInteract);
|
||||||
SubscribeLocalEvent<DrinkComponent, ExaminedEvent>(OnExamined);
|
SubscribeLocalEvent<DrinkComponent, ExaminedEvent>(OnExamined);
|
||||||
SubscribeLocalEvent<SharedBodyComponent, ForceDrinkEvent>(OnForceDrink);
|
SubscribeLocalEvent<SharedBodyComponent, ForceDrinkEvent>(OnForceDrink);
|
||||||
SubscribeLocalEvent<ForceDrinkCancelledEvent>(OnForceDrinkCancelled);
|
SubscribeLocalEvent<ForceDrinkCancelledEvent>(OnForceDrinkCancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the user is currently forcing someone do drink, this cancels the attempt if they swap hands or
|
||||||
|
/// otherwise loose the item. Prevents force-feeding dual-wielding.
|
||||||
|
/// </summary>
|
||||||
|
private void OnDrinkDeselected(EntityUid uid, DrinkComponent component, HandDeselectedEvent args)
|
||||||
|
{
|
||||||
|
if (component.CancelToken != null)
|
||||||
|
{
|
||||||
|
component.CancelToken.Cancel();
|
||||||
|
component.CancelToken = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsEmpty(EntityUid uid, DrinkComponent? component = null)
|
public bool IsEmpty(EntityUid uid, DrinkComponent? component = null)
|
||||||
{
|
{
|
||||||
if(!Resolve(uid, ref component))
|
if(!Resolve(uid, ref component))
|
||||||
@@ -240,6 +255,14 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
if (!Resolve(uid, ref drink))
|
if (!Resolve(uid, ref drink))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// if currently being used to force-feed, cancel that action.
|
||||||
|
if (drink.CancelToken != null)
|
||||||
|
{
|
||||||
|
drink.CancelToken.Cancel();
|
||||||
|
drink.CancelToken = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!drink.Opened)
|
if (!drink.Opened)
|
||||||
{
|
{
|
||||||
_popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-not-open",
|
_popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-not-open",
|
||||||
@@ -312,8 +335,12 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// cannot stack do-afters
|
// cannot stack do-afters
|
||||||
if (drink.InUse)
|
if (drink.CancelToken != null)
|
||||||
return false;
|
{
|
||||||
|
drink.CancelToken.Cancel();
|
||||||
|
drink.CancelToken = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!EntityManager.HasComponent<SharedBodyComponent>(targetUid))
|
if (!EntityManager.HasComponent<SharedBodyComponent>(targetUid))
|
||||||
return false;
|
return false;
|
||||||
@@ -342,7 +369,8 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
_popupSystem.PopupEntity(Loc.GetString("drink-component-force-feed", ("user", userName)),
|
_popupSystem.PopupEntity(Loc.GetString("drink-component-force-feed", ("user", userName)),
|
||||||
userUid, Filter.Entities(targetUid));
|
userUid, Filter.Entities(targetUid));
|
||||||
|
|
||||||
_doAfterSystem.DoAfter(new DoAfterEventArgs(userUid, drink.ForceFeedDelay, target: targetUid)
|
drink.CancelToken = new();
|
||||||
|
_doAfterSystem.DoAfter(new DoAfterEventArgs(userUid, drink.ForceFeedDelay, drink.CancelToken.Token, targetUid)
|
||||||
{
|
{
|
||||||
BreakOnUserMove = true,
|
BreakOnUserMove = true,
|
||||||
BreakOnDamage = true,
|
BreakOnDamage = true,
|
||||||
@@ -350,7 +378,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
BreakOnTargetMove = true,
|
BreakOnTargetMove = true,
|
||||||
MovementThreshold = 1.0f,
|
MovementThreshold = 1.0f,
|
||||||
TargetFinishedEvent = new ForceDrinkEvent(userUid, drink, drinkSolution),
|
TargetFinishedEvent = new ForceDrinkEvent(userUid, drink, drinkSolution),
|
||||||
BroadcastCancelledEvent = new ForceDrinkCancelledEvent(drink)
|
BroadcastCancelledEvent = new ForceDrinkCancelledEvent(drink),
|
||||||
});
|
});
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
@@ -359,7 +387,6 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
var drinkable = EntityManager.GetEntity(uid);
|
var drinkable = EntityManager.GetEntity(uid);
|
||||||
_logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{user} is forcing {target} to drink {drinkable}");
|
_logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{user} is forcing {target} to drink {drinkable}");
|
||||||
|
|
||||||
drink.InUse = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +395,10 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnForceDrink(EntityUid uid, SharedBodyComponent body, ForceDrinkEvent args)
|
private void OnForceDrink(EntityUid uid, SharedBodyComponent body, ForceDrinkEvent args)
|
||||||
{
|
{
|
||||||
args.Drink.InUse = false;
|
if (args.Drink.Deleted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Drink.CancelToken = null;
|
||||||
var transferAmount = FixedPoint2.Min(args.Drink.TransferAmount, args.DrinkSolution.DrainAvailable);
|
var transferAmount = FixedPoint2.Min(args.Drink.TransferAmount, args.DrinkSolution.DrainAvailable);
|
||||||
var drained = _solutionContainerSystem.Drain(args.Drink.OwnerUid, args.DrinkSolution, transferAmount);
|
var drained = _solutionContainerSystem.Drain(args.Drink.OwnerUid, args.DrinkSolution, transferAmount);
|
||||||
|
|
||||||
@@ -414,7 +444,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
|
|
||||||
private void OnForceDrinkCancelled(ForceDrinkCancelledEvent args)
|
private void OnForceDrinkCancelled(ForceDrinkCancelledEvent args)
|
||||||
{
|
{
|
||||||
args.Drink.InUse = false;
|
args.Drink.CancelToken = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using Content.Server.Popups;
|
|||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Chemistry.Components;
|
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
@@ -23,10 +22,10 @@ using Robust.Shared.IoC;
|
|||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Content.Server.Inventory.Components;
|
using Content.Server.Inventory.Components;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.Hands;
|
||||||
|
|
||||||
namespace Content.Server.Nutrition.EntitySystems
|
namespace Content.Server.Nutrition.EntitySystems
|
||||||
{
|
{
|
||||||
@@ -50,12 +49,26 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
|
|
||||||
SubscribeLocalEvent<FoodComponent, UseInHandEvent>(OnUseFoodInHand);
|
SubscribeLocalEvent<FoodComponent, UseInHandEvent>(OnUseFoodInHand);
|
||||||
SubscribeLocalEvent<FoodComponent, AfterInteractEvent>(OnFeedFood);
|
SubscribeLocalEvent<FoodComponent, AfterInteractEvent>(OnFeedFood);
|
||||||
|
SubscribeLocalEvent<FoodComponent, HandDeselectedEvent>(OnFoodDeselected);
|
||||||
SubscribeLocalEvent<FoodComponent, GetInteractionVerbsEvent>(AddEatVerb);
|
SubscribeLocalEvent<FoodComponent, GetInteractionVerbsEvent>(AddEatVerb);
|
||||||
SubscribeLocalEvent<SharedBodyComponent, ForceFeedEvent>(OnForceFeed);
|
SubscribeLocalEvent<SharedBodyComponent, ForceFeedEvent>(OnForceFeed);
|
||||||
SubscribeLocalEvent<ForceFeedCancelledEvent>(OnForceFeedCancelled);
|
SubscribeLocalEvent<ForceFeedCancelledEvent>(OnForceFeedCancelled);
|
||||||
SubscribeLocalEvent<InventoryComponent, IngestionAttemptEvent>(OnInventoryIngestAttempt);
|
SubscribeLocalEvent<InventoryComponent, IngestionAttemptEvent>(OnInventoryIngestAttempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the user is currently force feeding someone, this cancels the attempt if they swap hands or otherwise
|
||||||
|
/// loose the item. Prevents force-feeding dual-wielding.
|
||||||
|
/// </summary>
|
||||||
|
private void OnFoodDeselected(EntityUid uid, FoodComponent component, HandDeselectedEvent args)
|
||||||
|
{
|
||||||
|
if (component.CancelToken != null)
|
||||||
|
{
|
||||||
|
component.CancelToken.Cancel();
|
||||||
|
component.CancelToken = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Eat item
|
/// Eat item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -120,6 +133,14 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
if (!Resolve(uid, ref component))
|
if (!Resolve(uid, ref component))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// if currently being used to force-feed, cancel that action.
|
||||||
|
if (component.CancelToken != null)
|
||||||
|
{
|
||||||
|
component.CancelToken.Cancel();
|
||||||
|
component.CancelToken = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (uid == userUid || //Suppresses self-eating
|
if (uid == userUid || //Suppresses self-eating
|
||||||
EntityManager.TryGetComponent<MobStateComponent>(uid, out var mobState) && mobState.IsAlive()) // Suppresses eating alive mobs
|
EntityManager.TryGetComponent<MobStateComponent>(uid, out var mobState) && mobState.IsAlive()) // Suppresses eating alive mobs
|
||||||
return false;
|
return false;
|
||||||
@@ -214,6 +235,9 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
|
|
||||||
private void AddEatVerb(EntityUid uid, FoodComponent component, GetInteractionVerbsEvent ev)
|
private void AddEatVerb(EntityUid uid, FoodComponent component, GetInteractionVerbsEvent ev)
|
||||||
{
|
{
|
||||||
|
if (component.CancelToken != null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (uid == ev.UserUid ||
|
if (uid == ev.UserUid ||
|
||||||
!ev.CanInteract ||
|
!ev.CanInteract ||
|
||||||
!ev.CanAccess ||
|
!ev.CanAccess ||
|
||||||
@@ -244,6 +268,14 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
if (!Resolve(uid, ref food))
|
if (!Resolve(uid, ref food))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// if currently being used to force-feed, cancel that action.
|
||||||
|
if (food.CancelToken != null)
|
||||||
|
{
|
||||||
|
food.CancelToken.Cancel();
|
||||||
|
food.CancelToken = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!EntityManager.HasComponent<SharedBodyComponent>(targetUid))
|
if (!EntityManager.HasComponent<SharedBodyComponent>(targetUid))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -270,7 +302,8 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
_popupSystem.PopupEntity(Loc.GetString("food-system-force-feed", ("user", userName)),
|
_popupSystem.PopupEntity(Loc.GetString("food-system-force-feed", ("user", userName)),
|
||||||
userUid, Filter.Entities(targetUid));
|
userUid, Filter.Entities(targetUid));
|
||||||
|
|
||||||
_doAfterSystem.DoAfter(new DoAfterEventArgs(userUid, food.ForceFeedDelay, target: targetUid)
|
food.CancelToken = new();
|
||||||
|
_doAfterSystem.DoAfter(new DoAfterEventArgs(userUid, food.ForceFeedDelay, food.CancelToken.Token, targetUid)
|
||||||
{
|
{
|
||||||
BreakOnUserMove = true,
|
BreakOnUserMove = true,
|
||||||
BreakOnDamage = true,
|
BreakOnDamage = true,
|
||||||
@@ -287,13 +320,15 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
var edible = EntityManager.GetEntity(uid);
|
var edible = EntityManager.GetEntity(uid);
|
||||||
_logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{user} is forcing {target} to eat {edible}");
|
_logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{user} is forcing {target} to eat {edible}");
|
||||||
|
|
||||||
food.InUse = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnForceFeed(EntityUid uid, SharedBodyComponent body, ForceFeedEvent args)
|
private void OnForceFeed(EntityUid uid, SharedBodyComponent body, ForceFeedEvent args)
|
||||||
{
|
{
|
||||||
args.Food.InUse = false;
|
if (args.Food.Deleted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Food.CancelToken = null;
|
||||||
|
|
||||||
if (!_bodySystem.TryGetComponentsOnMechanisms<StomachComponent>(uid, out var stomachs, body))
|
if (!_bodySystem.TryGetComponentsOnMechanisms<StomachComponent>(uid, out var stomachs, body))
|
||||||
return;
|
return;
|
||||||
@@ -433,7 +468,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
|
|
||||||
private void OnForceFeedCancelled(ForceFeedCancelledEvent args)
|
private void OnForceFeedCancelled(ForceFeedCancelledEvent args)
|
||||||
{
|
{
|
||||||
args.Food.InUse = false;
|
args.Food.CancelToken = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user