Issue Data
|
Issue #28303: bos100fightmonitor: Unable to call IsDead/Cannot check for detection LOS with a None target
[12/28/2019 - 05:07:15PM] error: Unable to call IsDead - no native object bound to the script object, or object is of incorrect type
stack: [<nullptr form> (FF000DC6)].Actor.IsDead() - "<native>" Line ? [BoS100Fight (00068D7B)].bos100fightmonitor.GetCountOfLivingGhouls() - "C:\Users\Dr. Peter Haas\AppData\Local\Temp\PapyrusTemp\bos100fightmonitor.psc" Line 445 [BoS100Fight (00068D7B)].bos100fightmonitor.OnTimer() - "C:\Users\Dr. Peter Haas\AppData\Local\Temp\PapyrusTemp\bos100fightmonitor.psc" Line 333 [12/28/2019 - 05:07:15PM] warning: Assigning None to a non-object variable named "::temp108" stack: [BoS100Fight (00068D7B)].bos100fightmonitor.GetCountOfLivingGhouls() - "C:\Users\Dr. Peter Haas\AppData\Local\Temp\PapyrusTemp\bos100fightmonitor.psc" Line 445 [BoS100Fight (00068D7B)].bos100fightmonitor.OnTimer() - "C:\Users\Dr. Peter Haas\AppData\Local\Temp\PapyrusTemp\bos100fightmonitor.psc" Line 333 [12/28/2019 - 05:07:22PM] error: Cannot check for detection LOS with a None target stack: [ (00000014)].Actor.HasDetectionLOS() - "<native>" Line ? [BoS100Fight (00068D7B)].bos100fightmonitor.ForceKillGhouls() - "C:\Users\Dr. Peter Haas\AppData\Local\Temp\PapyrusTemp\bos100fightmonitor.psc" Line 462 [BoS100Fight (00068D7B)].bos100fightmonitor.OnTimer() - "C:\Users\Dr. Peter Haas\AppData\Local\Temp\PapyrusTemp\bos100fightmonitor.psc" Line 368 Note: These appear to be stuck in an endless loop, which gives you a really large papyrus log file. Mine was around 6.5 MB after playing for 2 hours. I'm not sure what triggered the issue, but it could have something to do with not talking to Paladin Danse immediately after killing all of the feral ghouls at the Cambridge Police Station (just a guess). |
The script has safety checks for NONE values in all the right places, but this looks like it's trying to reference deleted ones as well. Perhaps adding IsDeleted() checks in the same places will reduce the chances of this happening?
Just came here to report this myself.
This is a lower-level engine issue where the engine occasionally garbage collects the base ObjectReference forms to without also cleaning up their ObjectReference (and Actor and any other scripts that used to be attached) script instances. The engine, at least as far back as Skyrim, has a tendency to prematurely garbage collect anything spawned by PlaceAtMe() called with either abForcePersist = false, or maybe abDeleteWhenAble = true, I'm not sure. This happens very rarely, so it's extremely difficult to investigate in detail. Anyway, IsDeleted() won't work (it'll come back false because the function will fail completely, and print another <nullptr form> error to the log), nor will checking for None (because the script instance does exist, ergo is not None).
There are two ways to fix this: changing the PlaceAtMe calls so abForcePersist = true and abDeleteWhenAble = false will fix the "underlying" issue, but will not retroactively fix affected saves, and you'd need to carefully audit the script to be absolutely certain that anything spawned is manually Delete()d at some point, otherwise the script could cause save bloat.
The easier way to deal with this is to add checks for IsBoundGameObjectAvailable(), like so (starting at like 440):
However, it gets worse. Much worse. Because the original spawned FormIDs of the garbage collected ghouls may be recycled, if the save goes on for a while, the ghoul references in the array (such as, in OP's case, FF000DC6) may end up pointing to a new object, instead of just nothing.
In my case, after fixing the previous thing, I had this error:
And when I prid'd FF00133F, it was actually a (deleted) instance of the Nuclear Launch Key from Far Harbor that some other script had spawned in at some point. Which, oh my god, BoS100FightMonitor disabled and deleted via CleanupGhouls() at some point, because the key ended up in the AllGhouls array!!! Which means that this script can actually cause entirely random spawned references to disappear from the game, and who knows what else.
So, with that in mind, this is a serious bug that must be properly fixed. So, I have:
In my own save, loading up the game with my fix in place prints this out to my Papyrus log:
Unfortunately this also raises the issue of: where else in the game can this PlaceAtMe() issue ultimately rise up? A quick file search for calls to this function reveal ~400 other instances of this function being used, any one of which could potentially cause similar issues, and none of which are trivial fixes. Ugh...
Attached Files:
Scripts.7z
This is a lower-level engine issue where the engine occasionally garbage collects the base ObjectReference forms to without also cleaning up their ObjectReference (and Actor and any other scripts that used to be attached) script instances. The engine, at least as far back as Skyrim, has a tendency to prematurely garbage collect anything spawned by PlaceAtMe() called with either abForcePersist = false, or maybe abDeleteWhenAble = true, I'm not sure. This happens very rarely, so it's extremely difficult to investigate in detail. Anyway, IsDeleted() won't work (it'll come back false because the function will fail completely, and print another <nullptr form> error to the log), nor will checking for None (because the script instance does exist, ergo is not None).
There are two ways to fix this: changing the PlaceAtMe calls so abForcePersist = true and abDeleteWhenAble = false will fix the "underlying" issue, but will not retroactively fix affected saves, and you'd need to carefully audit the script to be absolutely certain that anything spawned is manually Delete()d at some point, otherwise the script could cause save bloat.
The easier way to deal with this is to add checks for IsBoundGameObjectAvailable(), like so (starting at like 440):
int Function GetCountOfLivingGhouls() int i = 0 int ghoulCount While (i < indexAllGhouls) ;Debug.Trace("GetCountOfLivingGhouls at " + i + ": " + AllGhouls[i ]) if (AllGhouls[i ] != None && AllGhouls[i ].IsBoundGameObjectAvailable() && !AllGhouls[i ].IsDead()) ghoulCount = ghoulCount + 1 EndIf i = i + 1 EndWhile ;Debug.Trace("GetCountOfLivingGhouls="+ghoulCount) return ghoulCount EndFunction(ignore the weirdly formatted [i ]s, just avoiding them being picked up as bbcode)
However, it gets worse. Much worse. Because the original spawned FormIDs of the garbage collected ghouls may be recycled, if the save goes on for a while, the ghoul references in the array (such as, in OP's case, FF000DC6) may end up pointing to a new object, instead of just nothing.
In my case, after fixing the previous thing, I had this error:
[07/23/2020 - 11:20:25AM] error: Unable to call Kill - no native object bound to the script object, or object is of incorrect type stack: [ (FF00133F)].Actor.Kill() - "<native>" Line ? [BoS100Fight (00068D7B)].bos100fightmonitor.ForceKillGhouls() - "C:\Program Files (x86)\Steam\steamapps\common\Fallout 4\Data\Scripts\Source\User\BoS100FightMonitor.psc" Line 469 [BoS100Fight (00068D7B)].bos100fightmonitor.OnTimer() - "C:\Program Files (x86)\Steam\steamapps\common\Fallout 4\Data\Scripts\Source\User\BoS100FightMonitor.psc" Line 368
And when I prid'd FF00133F, it was actually a (deleted) instance of the Nuclear Launch Key from Far Harbor that some other script had spawned in at some point. Which, oh my god, BoS100FightMonitor disabled and deleted via CleanupGhouls() at some point, because the key ended up in the AllGhouls array!!! Which means that this script can actually cause entirely random spawned references to disappear from the game, and who knows what else.
So, with that in mind, this is a serious bug that must be properly fixed. So, I have:
- Fixed the one place where PlaceAtMe() is called so abForcePersist = true and abDeleteWhenAble = false
- Made sure that anything spawned by PlaceAtMe() is explicitly Delete()d at some point
- Added a VerifyAllGhoulsArray() function that makes sure everything in AllGhouls really is a ghoul before attempting to operate on it
- Added a skipUFO4Pretroactive bool that will skip the extra processing required by VerifyAllGhoulsArray() in new games, which won't be affected by the underlying bug anymore (performance optimization)
In my own save, loading up the game with my fix in place prints this out to my Papyrus log:
[07/23/2020 - 12:52:07PM] [bos100fightmonitor <BoS100Fight (00068D7B)>] UFO4P: Cleaned out index 11=[Actor < (FF00133F)>] from AllGhouls array that doesn't point to a ghoul anymore [07/23/2020 - 12:52:07PM] [bos100fightmonitor <BoS100Fight (00068D7B)>] UFO4P: Cleaned out index 10=[Actor <<nullptr form> (FF001332)>] from AllGhouls array that's no longer bound to a game objectNo related errors print to my log anymore, and the infinitely looping timer has also correctly stopped.
Unfortunately this also raises the issue of: where else in the game can this PlaceAtMe() issue ultimately rise up? A quick file search for calls to this function reveal ~400 other instances of this function being used, any one of which could potentially cause similar issues, and none of which are trivial fixes. Ugh...
Attached Files:
Scripts.7z
Better late than never to get this one incorporated. What a nasty little mess. Hopefully this is also going to indirectly fix the associated BOS100Fight quest getting stuck as this seems like a likely reason it could happen. I don't think premature culling is limited to just objects spawned this way either as CK placed corpses often get purged before they should be too.
Showing Comments 1 - 3 of 3