Ludeon Forums

RimWorld => Mods => Help => Topic started by: Basker_ville on June 26, 2022, 03:35:37 PM

Title: Is there a way to exempt a pawn from Ideology's funeral-ritual notifications?
Post by: Basker_ville on June 26, 2022, 03:35:37 PM
There's a bug that was introduced in RimWorld's latest patch (June 6th 2022 - v1.3.3387). In this patch several Ideology improvements and fixes were made. One such change created this situational but annoying bug.

The error only presents with Ideology active, and it concerns some mods which override "HediffComp.Notify_PawnDied()" in order to change or resurrect human pawns at the moment of their death. Examples include Witcher - Monster Hunt (lycanthropy), Vanilla Cooking Expanded (resurrecter condiment), and others.

When a member of the player's Ideology dies, and the Notify_PawnDied() override is triggered (leading to either a transformation or resurrection) a red error occurs:

Full Stacktrace of a colonist being killed and resurrecting immediately:
Error in Precept.Notify_MemberDied(): System.NullReferenceException: Object reference not set to an instance of an object
  at RimWorld.RitualObligationTargetWorker_GraveWithTarget.LabelExtraPart (RimWorld.RitualObligation obligation) [0x0000b] in <81af9f8a18324e17b286924a43555a7c>:0
  at RimWorld.RitualObligation.get_LetterLabel () [0x00000] in <81af9f8a18324e17b286924a43555a7c>:0
  at RimWorld.Precept_Ritual.AddObligation (RimWorld.RitualObligation obligation) [0x00216] in <81af9f8a18324e17b286924a43555a7c>:0
  at RimWorld.RitualObligationTrigger_MemberDied.Notify_MemberDied (Verse.Pawn p) [0x0006e] in <81af9f8a18324e17b286924a43555a7c>:0
  at RimWorld.Precept_Ritual.Notify_MemberDied (Verse.Pawn p) [0x00025] in <81af9f8a18324e17b286924a43555a7c>:0
  at RimWorld.Ideo.Notify_MemberDied (Verse.Pawn member) [0x00011] in <81af9f8a18324e17b286924a43555a7c>:0
UnityEngine.StackTraceUtility:ExtractStackTrace ()
Verse.Log:Error (string)
RimWorld.Ideo:Notify_MemberDied (Verse.Pawn)
(wrapper dynamic-method) Verse.Pawn:Verse.Pawn.Kill_Patch4 (Verse.Pawn,System.Nullable`1<Verse.DamageInfo>,Verse.Hediff)
(wrapper dynamic-method) Verse.Pawn_HealthTracker:Verse.Pawn_HealthTracker.CheckForStateChange_Patch2 (Verse.Pawn_HealthTracker,System.Nullable`1<Verse.DamageInfo>,Verse.Hediff)
(wrapper dynamic-method) Verse.Pawn_HealthTracker:Verse.Pawn_HealthTracker.AddHediff_Patch2 (Verse.Pawn_HealthTracker,Verse.Hediff,Verse.BodyPartRecord,System.Nullable`1<Verse.DamageInfo>,Verse.DamageWorker/DamageResult)
Verse.Pawn_HealthTracker:PostApplyDamage (Verse.DamageInfo,single)
Verse.Pawn:PostApplyDamage (Verse.DamageInfo,single)
(wrapper dynamic-method) Verse.Thing:Verse.Thing.TakeDamage_Patch5 (Verse.Thing,Verse.DamageInfo)
RimWorld.Verb_MeleeAttackDamage:ApplyMeleeDamageToTarget (Verse.LocalTargetInfo)
RimWorld.Verb_MeleeAttack:TryCastShot ()
Verse.Verb:TryCastNextBurstShot ()
Verse.Verb:WarmupComplete ()
(wrapper dynamic-method) Verse.Verb:Verse.Verb.TryStartCastOn_Patch2 (Verse.Verb,Verse.LocalTargetInfo,Verse.LocalTargetInfo,bool,bool,bool)
(wrapper dynamic-method) Verse.Verb:Verse.Verb.TryStartCastOn_Patch1 (Verse.Verb,Verse.LocalTargetInfo,bool,bool,bool)
RimWorld.Pawn_MeleeVerbs:TryMeleeAttack (Verse.Thing,Verse.Verb,bool)
Verse.AI.JobDriver_AttackMelee:<MakeNewToils>b__3_1 ()
Verse.AI.Toils_Combat/<>c__DisplayClass6_0:<FollowAndMeleeAttack>b__0 ()
Verse.AI.JobDriver:DriverTick ()
Verse.AI.Pawn_JobTracker:JobTrackerTick ()
Verse.Pawn:Tick ()
Verse.TickList:Tick ()
(wrapper dynamic-method) Verse.TickManager:Verse.TickManager.DoSingleTick_Patch2 (Verse.TickManager)
Verse.TickManager:TickManagerUpdate ()
Verse.Game:UpdatePlay ()
Verse.Root_Play:Update ()


The red error occurs because the corpse in the crosshairs of Notify_MemberDied() immediately vanishes. After modifying one affected mod so that the pawn's corpse was retained, there was no longer a red error. However, that solution is itself a problem as it doesn't make sense thematically to retain the corpse.

I used a program to detect any differences in some portions of assembly between RimWorld v1.3.3387 (current) and the previous version. There were no changes in RitualObligationTargetWorker_GraveWithTarget or RitualObligationTargetFilter (which contain LabelExtraPart()) between versions. There was a change in RitualObligation between versions: notably the addition of "public string LetterLabel" which includes a reference to LabelExtraPart(). This section of code reads:

public string LetterLabel
{
get
{
string text = this.precept.obligationTargetFilter.LabelExtraPart(this);
string result;
if (text.NullOrEmpty())
{
result = "RitualOpportunity".Translate(this.precept.LabelCap);
}
else
{
result = "RitualOpportunityFor".Translate(this.precept.LabelCap) + " " + text;
}
return result;
}
}


This seems to be the discrepancy between versions which in some way leads to this error. I don't understand why it would be the problem, because it contains a conditional statement for null or empty text. Maybe this section of code is executed at a time inconvenient for this method of changing a pawn? Maybe it invokes LabelExtraPart() before RitualObligationTargetWorker_GraveWithTarget.ObligationTargetsValid() can validate the target? But if a pawn is just obliterated at once with explosives there's no issue, so I don't understand why in this instance the corpse vanishing is a problem.

Any suggestions on circumventing this issue?

Is there a way to simply exempt a pawn or a pawn's corpse, specifically if they have a certain hediff, from Ritual Obligations or the Member_Died() notification, without having to cut them out of the ideology entirely?