fix(possess): don't destroy caster in Apply; defer possession to OnJumpCompleted to prevent PawnFlyer NRE

- CompAbilityEffect_Possess.Apply now only logs; DoPossession runs after landing
- Harden HediffComp_GestaltNode against null/destroyed pawn (tick/severity/overlord search/relations)
- Fix GestaltOverseer Notify_PostRemovedByDeath message condition (only when overlord died/destroyed and hive node alive)
This commit is contained in:
2026-02-12 17:39:58 +08:00
parent c04d0bdba6
commit 033a618921
4 changed files with 56 additions and 21 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -35,15 +35,21 @@ namespace ArachnaeSwarm
{
get
{
CompGestalt comp = Pawn.TryGetComp<CompGestalt>();
var pawn = Pawn;
if (pawn == null)
{
return tracker;
}
CompGestalt comp = pawn.TryGetComp<CompGestalt>();
if (comp != null)
{
return comp.GestaltTracker;
}
if (tracker == null && NodeType == GestaltNodeType.OverlordNode)
{
tracker = new Pawn_GestaltTracker(Pawn);
tracker = new Pawn_GestaltTracker(pawn);
}
return tracker;
}
@@ -59,6 +65,12 @@ namespace ArachnaeSwarm
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
var pawn = Pawn;
if (pawn == null)
{
return;
}
if (NodeType == GestaltNodeType.HiveNode)
{
@@ -69,9 +81,9 @@ namespace ArachnaeSwarm
}
// 定期寻找 OverlordNode
if (Pawn.IsColonist &&
Pawn.Spawned &&
!Pawn.Dead &&
if (pawn.IsColonist &&
pawn.Spawned &&
!pawn.Dead &&
Find.TickManager.TicksGame % 250 == 0)
{
TryFindOverlord();
@@ -86,6 +98,12 @@ namespace ArachnaeSwarm
{
if (NodeType != GestaltNodeType.HiveNode || parent == null)
return;
var pawn = Pawn;
if (pawn?.health == null)
{
return;
}
bool isConnected = IsConnectedToOverlord();
@@ -103,7 +121,7 @@ namespace ArachnaeSwarm
wasConnected = isConnected;
// 如果严重性改变需要重新计算Pawn的能力
Pawn.health.Notify_HediffChanged(parent);
pawn.health.Notify_HediffChanged(parent);
}
}
@@ -118,6 +136,12 @@ namespace ArachnaeSwarm
public void TryFindOverlord()
{
// 如果已经有Overlord更新连接状态并返回
var pawn = Pawn;
if (pawn == null || pawn.Dead || pawn.Destroyed)
{
return;
}
if (IsConnectedToOverlord())
{
UpdateSeverityBasedOnConnection();
@@ -125,7 +149,7 @@ namespace ArachnaeSwarm
}
// 如果Pawn当前不在地图上无法寻找Overlord
if (Pawn.Map == null)
if (pawn.Map == null)
{
return;
}
@@ -134,22 +158,23 @@ namespace ArachnaeSwarm
Pawn bestOverlord = null;
float bestScore = -1f;
foreach (Pawn pawn in Pawn.Map.mapPawns.FreeColonists)
foreach (Pawn candidate in pawn.Map.mapPawns.FreeColonists)
{
HediffComp_GestaltNode nodeComp = pawn.GetGestaltNodeComp();
HediffComp_GestaltNode nodeComp = candidate.GetGestaltNodeComp();
if (nodeComp?.NodeType == GestaltNodeType.OverlordNode &&
pawn != Pawn &&
!pawn.Dead &&
!pawn.Downed)
candidate != pawn &&
!candidate.Dead &&
!candidate.Downed &&
!candidate.Destroyed)
{
Pawn_GestaltTracker tracker = pawn.GestaltTracker();
if (tracker != null && tracker.CanControlPawn(Pawn))
Pawn_GestaltTracker tracker = candidate.GestaltTracker();
if (tracker != null && tracker.CanControlPawn(pawn))
{
float score = CalculateOverlordScore(pawn, tracker);
float score = CalculateOverlordScore(candidate, tracker);
if (score > bestScore)
{
bestScore = score;
bestOverlord = pawn;
bestOverlord = candidate;
}
}
}
@@ -158,7 +183,11 @@ namespace ArachnaeSwarm
// 找到合适的Overlord建立关系并更新严重性
if (bestOverlord != null)
{
Pawn.relations.AddDirectRelation(ARA_PawnRelationDefOf.ARA_GestaltOverseer, bestOverlord);
// Pawns being destroyed/vanished can temporarily have no relations tracker.
if (pawn.relations != null && ARA_PawnRelationDefOf.ARA_GestaltOverseer != null)
{
pawn.relations.AddDirectRelation(ARA_PawnRelationDefOf.ARA_GestaltOverseer, bestOverlord);
}
UpdateSeverityBasedOnConnection();
}
}
@@ -188,10 +217,16 @@ namespace ArachnaeSwarm
// 当Hediff被移除时如果连接到Overlord需要断开连接
if (NodeType == GestaltNodeType.HiveNode && IsConnectedToOverlord())
{
Pawn overlord = Pawn.GetOverlord();
var pawn = Pawn;
if (pawn?.relations == null || ARA_PawnRelationDefOf.ARA_GestaltOverseer == null)
{
return;
}
Pawn overlord = pawn.GetOverlord();
if (overlord != null)
{
Pawn.relations.RemoveDirectRelation(ARA_PawnRelationDefOf.ARA_GestaltOverseer, overlord);
pawn.relations.RemoveDirectRelation(ARA_PawnRelationDefOf.ARA_GestaltOverseer, overlord);
}
}
}

View File

@@ -83,7 +83,7 @@ namespace ArachnaeSwarm
}
}
if (overlord != null && hiveNode != null && (!overlord.Dead || overlord.Destroyed))
if (overlord != null && hiveNode != null && !hiveNode.Dead && (overlord.Dead || overlord.Destroyed))
{
Messages.Message("MessageGestaltLostControl".Translate(overlord, hiveNode) + ": " + hiveNode.LabelShortCap,
new LookTargets(new Thing[] { overlord, hiveNode }), MessageTypeDefOf.NeutralEvent);