Fix NPC shutdown crash (#2971)

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
This commit is contained in:
metalgearsloth
2021-01-11 01:24:03 +11:00
committed by GitHub
parent 7bfdf30268
commit d403a7fab4
10 changed files with 67 additions and 49 deletions

View File

@@ -5,38 +5,36 @@ namespace Content.Server.AI.Operators
{ {
public abstract class AiOperator public abstract class AiOperator
{ {
public bool HasStartup => _hasStartup; public bool HasStartup { get; private set; }
private bool _hasStartup = false;
private bool _hasShutdown = false; public bool HasShutdown { get; private set; }
/// <summary> /// <summary>
/// Called once when the AiLogicProcessor starts this action /// Called once when the AiLogicProcessor starts this action
/// </summary> /// </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 // If we've already startup then no point continuing
// This signals to the override that it's already startup // This signals to the override that it's already startup
// Should probably throw but it made some code elsewhere marginally easier // Should probably throw but it made some code elsewhere marginally easier
if (_hasStartup) if (HasStartup)
{
return false; return false;
}
HasStartup = true;
_hasStartup = true;
return true; return true;
} }
/// <summary> /// <summary>
/// Called once when the AiLogicProcessor is done with this action if the outcome is successful or fails. /// Called once when the AiLogicProcessor is done with this action if the outcome is successful or fails.
/// </summary> /// </summary>
public virtual void Shutdown(Outcome outcome) public virtual bool Shutdown(Outcome outcome)
{ {
if (_hasShutdown) if (HasShutdown)
{ return false;
throw new InvalidOperationException("AiOperator has already shutdown");
}
_hasShutdown = true; HasShutdown = true;
return true;
} }
/// <summary> /// <summary>
@@ -53,4 +51,4 @@ namespace Content.Server.AI.Operators
Continuing, Continuing,
Failed, Failed,
} }
} }

View File

@@ -22,9 +22,9 @@ namespace Content.Server.AI.Operators.Combat.Melee
_burstTime = burstTime; _burstTime = burstTime;
} }
public override bool TryStartup() public override bool Startup()
{ {
if (!base.TryStartup()) if (!base.Startup())
{ {
return true; return true;
} }
@@ -42,13 +42,17 @@ namespace Content.Server.AI.Operators.Combat.Melee
return true; 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)) if (_owner.TryGetComponent(out CombatModeComponent combatModeComponent))
{ {
combatModeComponent.IsInCombatMode = false; combatModeComponent.IsInCombatMode = false;
} }
return true;
} }
public override Outcome Execute(float frameTime) public override Outcome Execute(float frameTime)

View File

@@ -22,9 +22,9 @@ namespace Content.Server.AI.Operators.Combat.Melee
_burstTime = burstTime; _burstTime = burstTime;
} }
public override bool TryStartup() public override bool Startup()
{ {
if (!base.TryStartup()) if (!base.Startup())
{ {
return true; return true;
} }
@@ -51,13 +51,17 @@ namespace Content.Server.AI.Operators.Combat.Melee
return true; 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)) if (_owner.TryGetComponent(out CombatModeComponent combatModeComponent))
{ {
combatModeComponent.IsInCombatMode = false; combatModeComponent.IsInCombatMode = false;
} }
return true;
} }
public override Outcome Execute(float frameTime) public override Outcome Execute(float frameTime)

View File

@@ -21,9 +21,9 @@ namespace Content.Server.AI.Operators.Inventory
_owner = owner; _owner = owner;
} }
public override bool TryStartup() public override bool Startup()
{ {
if (!base.TryStartup()) if (!base.Startup())
{ {
return true; return true;
} }
@@ -40,12 +40,15 @@ namespace Content.Server.AI.Operators.Inventory
return _target != null; 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); var blackboard = UtilityAiHelpers.GetBlackboard(_owner);
blackboard?.GetState<LastOpenedStorageState>().SetValue(null); blackboard?.GetState<LastOpenedStorageState>().SetValue(null);
return true;
} }
public override Outcome Execute(float frameTime) public override Outcome Execute(float frameTime)

View File

@@ -32,9 +32,9 @@ namespace Content.Server.AI.Operators.Movement
_requiresInRangeUnobstructed = requiresInRangeUnobstructed; _requiresInRangeUnobstructed = requiresInRangeUnobstructed;
} }
public override bool TryStartup() public override bool Startup()
{ {
if (!base.TryStartup()) if (!base.Startup())
{ {
return true; return true;
} }
@@ -45,11 +45,14 @@ namespace Content.Server.AI.Operators.Movement
return true; 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>(); var steering = EntitySystem.Get<AiSteeringSystem>();
steering.Unregister(_owner); steering.Unregister(_owner);
return true;
} }
public override Outcome Execute(float frameTime) public override Outcome Execute(float frameTime)

View File

@@ -21,9 +21,9 @@ namespace Content.Server.AI.Operators.Movement
DesiredRange = desiredRange; DesiredRange = desiredRange;
} }
public override bool TryStartup() public override bool Startup()
{ {
if (!base.TryStartup()) if (!base.Startup())
{ {
return true; return true;
} }
@@ -34,11 +34,14 @@ namespace Content.Server.AI.Operators.Movement
return true; 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>(); var steering = EntitySystem.Get<AiSteeringSystem>();
steering.Unregister(_owner); steering.Unregister(_owner);
return true;
} }
public override Outcome Execute(float frameTime) public override Outcome Execute(float frameTime)

View File

@@ -17,9 +17,9 @@ namespace Content.Server.AI.Operators.Sequences
{ {
return Outcome.Success; return Outcome.Success;
} }
var op = Sequence.Peek(); var op = Sequence.Peek();
op.TryStartup(); op.Startup();
var outcome = op.Execute(frameTime); var outcome = op.Execute(frameTime);
switch (outcome) switch (outcome)
@@ -35,10 +35,10 @@ namespace Content.Server.AI.Operators.Sequences
op.Shutdown(outcome); op.Shutdown(outcome);
Sequence.Clear(); Sequence.Clear();
return Outcome.Failed; return Outcome.Failed;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
} }
} }
} }

View File

@@ -62,7 +62,7 @@ namespace Content.Server.AI.Utility.Actions
{ {
Owner = owner; Owner = owner;
} }
public virtual void Shutdown() {} public virtual void Shutdown() {}
/// <summary> /// <summary>
@@ -78,7 +78,7 @@ namespace Content.Server.AI.Utility.Actions
return Outcome.Success; return Outcome.Success;
} }
op.TryStartup(); op.Startup();
var outcome = op.Execute(frameTime); var outcome = op.Execute(frameTime);
switch (outcome) switch (outcome)
@@ -116,7 +116,7 @@ namespace Content.Server.AI.Utility.Actions
// Overall structure is based on Building a better centaur // 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 // 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. // the finalScore can only go down over time.
var finalScore = 1.0f; var finalScore = 1.0f;
var minThreshold = min / Bonus; var minThreshold = min / Bonus;
context.GetState<ConsiderationState>().SetValue(considerations.Count); context.GetState<ConsiderationState>().SetValue(considerations.Count);

View File

@@ -137,6 +137,8 @@ namespace Content.Server.AI.Utility.AiLogic
{ {
var currentOp = CurrentAction?.ActionOperators.Peek(); var currentOp = CurrentAction?.ActionOperators.Peek();
currentOp?.Shutdown(Outcome.Failed); currentOp?.Shutdown(Outcome.Failed);
CurrentAction?.Shutdown();
CurrentAction = null;
} }
public void MobStateChanged(MobStateChangedMessage message) public void MobStateChanged(MobStateChangedMessage message)

View File

@@ -110,17 +110,18 @@ namespace Content.Server.GameObjects.EntitySystems.AI
foreach (var processor in _awakeAi) foreach (var processor in _awakeAi)
{ {
if (count >= maxUpdates) if (processor.SelfEntity.Deleted ||
{ !processor.SelfEntity.HasComponent<AiControllerComponent>())
break;
}
if (processor.SelfEntity.Deleted)
{ {
toRemove.Add(processor); toRemove.Add(processor);
continue; continue;
} }
if (count >= maxUpdates)
{
break;
}
processor.Update(frameTime); processor.Update(frameTime);
count++; count++;
} }