Jump to content

[LE] Quests dropping aliases filled with ForceRefTo between loads.


Recommended Posts

@xkkmEl Yes, OnInit() fires multiple times, depending on the case. But I don't think this fact relates to the observed issue: The issue shows regardless if you check "Run Once" or not (no stages in this quest).

What I wanted to say is that the (repeatable) observation is that when you use this version of OnInit() in a quest that is not "Start Game Enabled"

image.png.96a9fb3958619c631bd19832dfef1b86.png

the alias will be 100% cleared by save-game / reload-game steps. Ie the savegame is broken (BTW: as long as you continue to play after saving without reloading, the alias is still filled).

I consider the other version of OnInit() to be the expected behavior (ie alias to  100% remains filled in the Savegame):

image.png.a080f40024f85376b57eb79a4f4cdc98.png

I do not see a reason why those two versions of OnInit() should behave differently, so I consider this observation to be a bug in the game engine.

All the rest is guesswork on my end. My interpretation is that in case a quest is "Start Game Enabled", and one of the quest's RefAlias is filled via ForcRefTo() in OnInit(), this engine bug results in random alias clears in the savegames. "Random" because I assume that the sequence in which the engine is starting the quest and firing OnInit() (which is ForceRef'ing the alias) is not defined. And in case ForceRefTo is fired before Start, your next savegame will be broken.

So my suggested workaround for the (presumed) game engine bug is to not use "Start Game Enabled" in case you have to ForceRef Aliases during OnInit(), because then you do not have control over the sequence in which Start and ForceRef are handled. If you instead de-activate "Start Game Enabled", and start the quest via OnInit () (possibly gated by checking for IsRunning() ), you have control over the sequence and therefore can navigate around the bug, while still effectively starting the quest immediately.

Better solution still would be to avoid ForceRef'ing the alias during OnInit() in the first place - if it's possible to delay filling it to a later function call; or if you can pass the reference directly as parameter value for the ReferenceAlias via the ESP instead.

 

Link to comment
Share on other sites

Well, call me Thomas.  I don't believe you, so I went in to see for myself.

I made a few tests, and well, I'm sorry to say there is indeed a game engine bug 🙂

It appears that in any situation where you start a quest with "Specific Reference, None" fill type, if the specific reference already has a value (that was forceRef'd while the quest is stopped), any new value you force into the alias after starting the quest will be replaced by None in the save file whereas the running game continues using the new value.

I even tried moving the forceRefTo outside of the OnInit (in an OnUpdate event) with the same result.

Specifically, what I observe is that the alias is reset to None when you start the quest.  If this reset actually clears a value that was forceRef'd while the quest was stopped, the None value will be propagated to the save file and any new forceRef'd values will be ignored by the save file.  I did not test to see how long this situation persists... it may return to normal is you save and reload, allowing new forceRef'd values to then reach the save file...

@staalo18 I'd like to point out that although your proposed solution of switching the 2 lines of code seems to work, you are likely still creating two objects.  I would suggest making the forceRefTo and placeAtMe conditional on getOwningQuest().isRunning() as a better fix.

Link to comment
Share on other sites

@xkkmElThanks much for these additional investigations and findings! I fully understand you were doubtful and needed to test yourself - that's what I usually do when I incorporate stuff I read somewhere (my real name actually IS Thomas :-)).

And yes, of course, the PlaceAtMe should better be fenced by isRunning() (and while we're at it, also check for IsStarting(), which catches the case where the startup phase is not yet completed):

image.png.5ea037ade8ab6ea9d4d9142c58817fb4.png

BTW, for my mod, I probably will end up replacing the ForceRefTo() approach with dropping the ObjectRef into Skyrim and then filling the ReferenceAlias with that ObjectReference via the Quest Dialogue, ie provide it as a property value directly in the CK. Even though this is a bit more effort for me, and overally may make my mod architecture somewhat more involved, that way I am completely avoiding any risk with ForceRefTo().

 

  • Haha 1
Link to comment
Share on other sites

My actual suggested code is:

event OnInit()
	if getOwningQuest().isRunning()
		forceRefTo( ...)
	else
		getOwningQuest().start()
	endif
endevent

I don't think the isStarting case is possible, though you can add "&& !getOwningQuest().isStarting()" to the if's condition.

If isRunning returns true, ".start()" is guaranteed to be a noop.  If not true, then you are guaranteed to get another OnInit with isRunning true.

Edit: I should have mentioned... I think your code will work as long as the quest is not SEQ.  Just felt like putting in my own version as well.

Edited by xkkmEl
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...