[1.3.3159] Blinding pulse psycast on humans causes infinite stat recursion error

Started by Commander Beanbag, November 17, 2021, 02:13:17 AM

Previous topic - Next topic

Commander Beanbag

Throwback to this bug report: https://ludeon.com/forums/index.php?topic=55167.0

That older report claims that the error only happens when blinding pawns with the Blindsight meme. This is not the case; it happens to any human.

Now for my own report. I was getting raided, threw down a blinding pulse psycast on the enemy. Then the errors began: one every time a psychically-blinded pawn got damaged. Interestingly, this error pauses the game every single time it's thrown, making combat rather tedious with blinding pulse being used. (alright, looks like I unknowningly clicked "pause when an error is logged"...)

I deleted the enemy pawns who were affected, and used blinding pulse on my own colonists. Same error, same conditions.

I was playing with some mods at the time, but went ahead and loaded this save with 0 mods, and saved again. This is the save I am uploading first, because the issue is still present.
It loads in mid-combat with bullets flying, blinding pulse already used, and the error happens almost immediately when I unpause. Hope it helps.
https://www.dropbox.com/s/dzfdrz53yte92x7/The%20Scarred%20Covenant%20infinite%20no%20mods.zip?dl=0

Detected infinite stat recursion when evaluating Sight
UnityEngine.StackTraceUtility:ExtractStackTrace ()
Verse.Log:Error (string)
Verse.PawnCapacitiesHandler:GetLevel (Verse.PawnCapacityDef)
RimWorld.StatPart_SightPsychicSenstivityOffset:TryGetPsychicOffset (Verse.Thing,single&)
RimWorld.StatPart_SightPsychicSenstivityOffset:TransformValue (RimWorld.StatRequest,single&)
RimWorld.StatWorker:FinalizeValue (RimWorld.StatRequest,single&,bool)
RimWorld.StatWorker:GetValue (RimWorld.StatRequest,bool)
RimWorld.StatWorker:GetValue (Verse.Thing,bool)
RimWorld.StatExtension:GetStatValue (Verse.Thing,RimWorld.StatDef,bool)
Verse.PawnCapacityUtility:CalculateCapacityLevel (Verse.HediffSet,Verse.PawnCapacityDef,System.Collections.Generic.List`1<Verse.PawnCapacityUtility/CapacityImpactor>,bool)
Verse.PawnCapacitiesHandler:GetLevel (Verse.PawnCapacityDef)
Verse.PawnCapacitiesHandler:CapableOf (Verse.PawnCapacityDef)
RimWorld.PawnUtility:IsBiologicallyBlind (Verse.Pawn)
RimWorld.PawnUtility:IsBiologicallyOrArtificallyBlind (Verse.Pawn)
RimWorld.ThoughtWorker_Pretty:CurrentSocialStateInternal (Verse.Pawn,Verse.Pawn)
RimWorld.ThoughtWorker:CurrentSocialState (Verse.Pawn,Verse.Pawn)
RimWorld.SituationalThoughtHandler:TryCreateSocialThought (RimWorld.ThoughtDef,Verse.Pawn)
RimWorld.SituationalThoughtHandler:CheckRecalculateSocialThoughts (Verse.Pawn)
RimWorld.SituationalThoughtHandler:AppendSocialThoughts (Verse.Pawn,System.Collections.Generic.List`1<RimWorld.ISocialThought>)
RimWorld.ThoughtHandler:GetSocialThoughts (Verse.Pawn,System.Collections.Generic.List`1<RimWorld.ISocialThought>)
RimWorld.ThoughtHandler:GetDistinctSocialThoughtGroups (Verse.Pawn,System.Collections.Generic.List`1<RimWorld.ISocialThought>)
RimWorld.ThoughtHandler:TotalOpinionOffset (Verse.Pawn)
RimWorld.Pawn_RelationsTracker:OpinionOf (Verse.Pawn)
RimWorld.LovePartnerRelationUtility:ExistingMostLikedLovePartnerRel (Verse.Pawn,bool)
RimWorld.ThoughtWorker_OpinionOfMyLover:CurrentStateInternal (Verse.Pawn)
RimWorld.ThoughtWorker:CurrentState (Verse.Pawn)
RimWorld.SituationalThoughtHandler:TryCreateThought (RimWorld.ThoughtDef)
RimWorld.SituationalThoughtHandler:CheckRecalculateMoodThoughts ()
RimWorld.SituationalThoughtHandler:AppendMoodThoughts (System.Collections.Generic.List`1<RimWorld.Thought>)
RimWorld.ThoughtHandler:GetAllMoodThoughts (System.Collections.Generic.List`1<RimWorld.Thought>)
RimWorld.ThoughtHandler:GetDistinctMoodThoughtGroups (System.Collections.Generic.List`1<RimWorld.Thought>)
RimWorld.ThoughtHandler:TotalMoodOffset ()
RimWorld.Need_Mood:get_CurInstantLevel ()
RimWorld.Need_Seeker:NeedInterval ()
RimWorld.Need_Mood:NeedInterval ()
RimWorld.Pawn_NeedsTracker:NeedsTrackerTick ()
Verse.Pawn:Tick ()
Verse.TickList:Tick ()
Verse.TickManager:DoSingleTick ()
Verse.TickManager:TickManagerUpdate ()
Verse.Game:UpdatePlay ()
Verse.Root_Play:Update ()

Pheanox

Thanks for the bug report.  I'll look into your save, though the fact that you are using a save that was modded, then stripped of mods could still be part of the problem, as they can leave lingering effects.  However I will investigate this and send something over to the devs to review.

colinfang

I understand it was reported before in an earlier version but it hasn't been resolved and no save was attached on that one.

Here I have the save before & after the blinding pulse to help debugging

https://drive.google.com/file/d/1N5boOu3577uHd2iVD-fTlW44bFLNFvW5/view?usp=sharing







RimWorld 1.3.3200 rev726
UnityEngine.StackTraceUtility:ExtractStackTrace ()
Verse.Log:Message (string)
RimWorld.VersionControl:LogVersionNumber ()
Verse.Root:CheckGlobalInit ()
Verse.Root:Start ()
Verse.Root_Entry:Start ()

Loading game from file test_after with mods:
  - Ludeon.RimWorld
  - Ludeon.RimWorld.Royalty
  - Ludeon.RimWorld.Ideology
UnityEngine.StackTraceUtility:ExtractStackTrace ()
Verse.Log:Message (string)
Verse.SavedGameLoaderNow:LoadGameFromSaveFileNow (string)
Verse.Root_Play/<>c:<Start>b__1_1 ()
Verse.LongEventHandler:RunEventFromAnotherThread (System.Action)
Verse.LongEventHandler/<>c:<UpdateCurrentAsynchronousEvent>b__27_0 ()
System.Threading.ThreadHelper:ThreadStart_Context (object)
System.Threading.ExecutionContext:RunInternal (System.Threading.ExecutionContext,System.Threading.ContextCallback,object,bool)
System.Threading.ExecutionContext:Run (System.Threading.ExecutionContext,System.Threading.ContextCallback,object,bool)
System.Threading.ExecutionContext:Run (System.Threading.ExecutionContext,System.Threading.ContextCallback,object)
System.Threading.ThreadHelper:ThreadStart ()

Detected infinite stat recursion when evaluating Sight
UnityEngine.StackTraceUtility:ExtractStackTrace ()
Verse.Log:Error (string)
Verse.PawnCapacitiesHandler:GetLevel (Verse.PawnCapacityDef)
RimWorld.StatPart_SightPsychicSenstivityOffset:TryGetPsychicOffset (Verse.Thing,single&)
RimWorld.StatPart_SightPsychicSenstivityOffset:TransformValue (RimWorld.StatRequest,single&)
RimWorld.StatWorker:FinalizeValue (RimWorld.StatRequest,single&,bool)
RimWorld.StatWorker:GetValue (RimWorld.StatRequest,bool)
RimWorld.StatWorker:GetValue (Verse.Thing,bool)
RimWorld.StatExtension:GetStatValue (Verse.Thing,RimWorld.StatDef,bool)
Verse.PawnCapacityUtility:CalculateCapacityLevel (Verse.HediffSet,Verse.PawnCapacityDef,System.Collections.Generic.List`1<Verse.PawnCapacityUtility/CapacityImpactor>,bool)
Verse.PawnCapacitiesHandler:GetLevel (Verse.PawnCapacityDef)
RimWorld.StatWorker:GetValueUnfinalized (RimWorld.StatRequest,bool)
RimWorld.StatWorker:GetValue (RimWorld.StatRequest,bool)
RimWorld.StatWorker:GetValue (Verse.Thing,bool)
RimWorld.StatExtension:GetStatValue (Verse.Thing,RimWorld.StatDef,bool)
RimWorld.Verb_MeleeAttack:GetDodgeChance (Verse.LocalTargetInfo)
RimWorld.Verb_MeleeAttack:TryCastShot ()
Verse.Verb:TryCastNextBurstShot ()
Verse.Verb:WarmupComplete ()
Verse.Verb:TryStartCastOn (Verse.LocalTargetInfo,Verse.LocalTargetInfo,bool,bool,bool)
Verse.Verb:TryStartCastOn (Verse.LocalTargetInfo,bool,bool,bool)
RimWorld.Pawn_MeleeVerbs:TryMeleeAttack (Verse.Thing,Verse.Verb,bool)
Verse.AI.JobDriver_Wait:CheckForAutoAttack ()
Verse.AI.JobDriver_Wait:Notify_StanceChanged ()
Verse.Pawn_StanceTracker:SetStance (Verse.Stance)
Verse.Stance_Busy:Expire ()
Verse.Stance_Busy:StanceTick ()
Verse.Pawn_StanceTracker:StanceTrackerTick ()
Verse.Pawn:Tick ()
Verse.TickList:Tick ()
Verse.TickManager:DoSingleTick ()
Verse.TickManager:TickManagerUpdate ()
Verse.Game:UpdatePlay ()
Verse.Root_Play:Update ()


Hmm, just skimming the code, I am not sure I understand how it manages to calculate the sight without issue in a normal game.

Bascially, in order to get the sight in `Verse.PawnCapacitiesHandler:GetLevel`, the game has to check each hediff.
Blinding pulse would add Hediff `PsychicBlindness`, which affects sight by `<capacityFactorEffectMultiplier>PsychicSensitivity</capacityFactorEffectMultiplier>`
Then the game checks `PsychicSensitivity` via `RimWorld.StatWorker:GetValue`
This stat has `StatPart_SightPsychicSenstivityOffset`, which requires sight in `TryGetPsychicOffset`, hence the infinite loop

glass zebra

Weird thing about that is that on things with psychic sensitivity mechanics like human is though, that the skill lowers the sight more than the stated value due to fact that a reduction in sight increases psychic sensitivity, but it does this directly on the first cast. There is no stacking after that or anything like that, so it's weird that there is a loop here indicating that it would just break.

Pheanox

Just a heads up, not all bugs that are fixed are published immediately.  Bugs deemed a 'priority' may go on the unstable branch, but the majority of bug reports are put into the internal branches and larger patches with many bugs are then released at later times.