Repository navigation
Conversation
Actor::Create ignored the result of ModManager::Spawn. When the game doesn't place the reference, the new Character keeps form ID 0 and gets no handle, so the GamePtr returned by Create holds its only reference. Callers store it in a raw Actor* and the actor is freed at the end of that statement, then moved with MoveTo and used as a remote actor. Engine work queued for it can later run on the freed actor, as in a crash at SkyrimSE 13641+0x47 under TESObjectREFR::MoveRefToNewSpace (19799) from BSTaskPool, with a form ID 0 "Deer" and no parent cell. Return null from Create when the spawn yields no handle or form ID. Callers already handle a null actor; the debug spawner now checks it too, and the spawn request drops the entity it created for the actor. Not verified in Ghidra and not built or tested in game. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018fvQxNnHTLXfMV8j1PBLiQ
Diagnostic for the SkyrimSE+1AF607 crash: the crashing Deer had form ID 0, and the client log shows Deer/Elk actors with form ID 0 being loaded just before it. Log the caller chain (module+offset) when a Character is constructed without a form ID and when one gets its 3D loaded, so the code creating these actors can be found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018fvQxNnHTLXfMV8j1PBLiQ
The owner streams positions from its own loaded area, which can lie past the edge of ours. Interpolation moved remote actors there anyway, so the game moved them into cells we don't have loaded and then into cells as they unloaded. Ghidra on 1.6.1170 shows the per-frame actor update (37352) queues task 0x54 with a raw copy of parentCell->worldspace when an actor leaves its exterior cell, and 19799/13641 later use it unchecked. A crash dump had that worldspace come from a parent cell that was no longer a cell. Hold remote actors at their last position inside the loaded grid until they come back or are removed. Interiors and other worldspaces are unchanged. Not tested in game. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018fvQxNnHTLXfMV8j1PBLiQ
Diagnostic for the follower spawn/remove loop (Esbern removed 6,183 times in one log): log the actor's and the player's cell, worldspace and position when an actor is added, before and after a remote actor is moved to its owner, and when it is removed, to show what brings it back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018fvQxNnHTLXfMV8j1PBLiQ
Holding a remote actor at the edge of the loaded area keeps it loaded and stuck there, so it never unloads the way Skyrim expects when an NPC walks off on its schedule. This reverts commit a299ac5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018fvQxNnHTLXfMV8j1PBLiQ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Eric · project thread
Status: this does not fix the SkyrimSE+1AF607 crash. It adds logging to find the cause, plus one unrelated hardening change.
Crash (what we know)
EXCEPTION_ACCESS_VIOLATIONat SkyrimSE.exe+1AF607 (1.6.1170, ID 13641+0x47) on a "Deer" Character with form ID 0. Crashes like it vary in where they happen, but all involve actors at the edge of the loaded area.Checked in Ghidra (1.6.1170):
BSTHashMapat worldspace+0x58). It was called with a pointer that isn't a live worldspace.parentCell, copyingparentCell->worldspace(+0x128) as a raw pointer. 19799 (MoveRefToNewSpace) later passes it to 13641 without checking it.parentCell, which no longer looked like a cell (form type 0, ID 0). The dump has no heap memory, so the Deer itself couldn't be inspected.Changes
[FormIdZeroActor]: logs a module+offset stack when a Character is constructed with form ID 0, or when one gets its 3D loaded. The client log showed form ID 0 Deer/Elk actors loaded and removed shortly before the crash.[ActorPlacement]: logs the actor's and the player's cell, worldspace and position when an actor is added, before and after a remote actor is moved to its owner, and when it is removed. This is to trace a spawn/remove loop on a follower that both saves share: Esbern was removed 6,183 times in one log.Actor::Createnow returns null whenModManager::Spawngives no handle or form ID. This is not the cause of this crash. Callers already handle null.Held remote actors at the edge of the loaded area (reverted): that keeps NPCs loaded and stuck there instead of letting them walk off on their schedules.
Both diagnostics are temporary and should be removed once the cause is found. Not tested in game.
🤖 Generated with Claude Code
https://claude.ai/code/session_018fvQxNnHTLXfMV8j1PBLiQ