Fix NPC shutdown crash (#2971)
Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
This commit is contained in:
@@ -5,38 +5,36 @@ namespace Content.Server.AI.Operators
|
||||
{
|
||||
public abstract class AiOperator
|
||||
{
|
||||
public bool HasStartup => _hasStartup;
|
||||
private bool _hasStartup = false;
|
||||
private bool _hasShutdown = false;
|
||||
public bool HasStartup { get; private set; }
|
||||
|
||||
public bool HasShutdown { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called once when the AiLogicProcessor starts this action
|
||||
/// </summary>
|
||||
public virtual bool TryStartup()
|
||||
/// <returns>true if it hasn't started up previously</returns>
|
||||
public virtual bool Startup()
|
||||
{
|
||||
// If we've already startup then no point continuing
|
||||
// This signals to the override that it's already startup
|
||||
// Should probably throw but it made some code elsewhere marginally easier
|
||||
if (_hasStartup)
|
||||
{
|
||||
if (HasStartup)
|
||||
return false;
|
||||
}
|
||||
|
||||
_hasStartup = true;
|
||||
|
||||
HasStartup = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called once when the AiLogicProcessor is done with this action if the outcome is successful or fails.
|
||||
/// </summary>
|
||||
public virtual void Shutdown(Outcome outcome)
|
||||
public virtual bool Shutdown(Outcome outcome)
|
||||
{
|
||||
if (_hasShutdown)
|
||||
{
|
||||
throw new InvalidOperationException("AiOperator has already shutdown");
|
||||
}
|
||||
if (HasShutdown)
|
||||
return false;
|
||||
|
||||
_hasShutdown = true;
|
||||
HasShutdown = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,4 +51,4 @@ namespace Content.Server.AI.Operators
|
||||
Continuing,
|
||||
Failed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace Content.Server.AI.Operators.Combat.Melee
|
||||
_burstTime = burstTime;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -42,13 +42,17 @@ namespace Content.Server.AI.Operators.Combat.Melee
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
if (_owner.TryGetComponent(out CombatModeComponent combatModeComponent))
|
||||
{
|
||||
combatModeComponent.IsInCombatMode = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace Content.Server.AI.Operators.Combat.Melee
|
||||
_burstTime = burstTime;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -51,13 +51,17 @@ namespace Content.Server.AI.Operators.Combat.Melee
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
if (_owner.TryGetComponent(out CombatModeComponent combatModeComponent))
|
||||
{
|
||||
combatModeComponent.IsInCombatMode = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -40,12 +40,15 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
return _target != null;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
var blackboard = UtilityAiHelpers.GetBlackboard(_owner);
|
||||
|
||||
blackboard?.GetState<LastOpenedStorageState>().SetValue(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -32,9 +32,9 @@ namespace Content.Server.AI.Operators.Movement
|
||||
_requiresInRangeUnobstructed = requiresInRangeUnobstructed;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -45,11 +45,14 @@ namespace Content.Server.AI.Operators.Movement
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
var steering = EntitySystem.Get<AiSteeringSystem>();
|
||||
steering.Unregister(_owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace Content.Server.AI.Operators.Movement
|
||||
DesiredRange = desiredRange;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -34,11 +34,14 @@ namespace Content.Server.AI.Operators.Movement
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
var steering = EntitySystem.Get<AiSteeringSystem>();
|
||||
steering.Unregister(_owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -17,9 +17,9 @@ namespace Content.Server.AI.Operators.Sequences
|
||||
{
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
|
||||
var op = Sequence.Peek();
|
||||
op.TryStartup();
|
||||
op.Startup();
|
||||
var outcome = op.Execute(frameTime);
|
||||
|
||||
switch (outcome)
|
||||
@@ -35,10 +35,10 @@ namespace Content.Server.AI.Operators.Sequences
|
||||
op.Shutdown(outcome);
|
||||
Sequence.Clear();
|
||||
return Outcome.Failed;
|
||||
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Content.Server.AI.Utility.Actions
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
|
||||
public virtual void Shutdown() {}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,7 +78,7 @@ namespace Content.Server.AI.Utility.Actions
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
op.TryStartup();
|
||||
op.Startup();
|
||||
var outcome = op.Execute(frameTime);
|
||||
|
||||
switch (outcome)
|
||||
@@ -116,7 +116,7 @@ namespace Content.Server.AI.Utility.Actions
|
||||
// Overall structure is based on Building a better centaur
|
||||
// Ideally we should early-out each action as cheaply as possible if it's not valid, thus
|
||||
// the finalScore can only go down over time.
|
||||
|
||||
|
||||
var finalScore = 1.0f;
|
||||
var minThreshold = min / Bonus;
|
||||
context.GetState<ConsiderationState>().SetValue(considerations.Count);
|
||||
|
||||
@@ -137,6 +137,8 @@ namespace Content.Server.AI.Utility.AiLogic
|
||||
{
|
||||
var currentOp = CurrentAction?.ActionOperators.Peek();
|
||||
currentOp?.Shutdown(Outcome.Failed);
|
||||
CurrentAction?.Shutdown();
|
||||
CurrentAction = null;
|
||||
}
|
||||
|
||||
public void MobStateChanged(MobStateChangedMessage message)
|
||||
|
||||
@@ -110,17 +110,18 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
||||
|
||||
foreach (var processor in _awakeAi)
|
||||
{
|
||||
if (count >= maxUpdates)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (processor.SelfEntity.Deleted)
|
||||
if (processor.SelfEntity.Deleted ||
|
||||
!processor.SelfEntity.HasComponent<AiControllerComponent>())
|
||||
{
|
||||
toRemove.Add(processor);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count >= maxUpdates)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
processor.Update(frameTime);
|
||||
count++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user