jimkaiseriv Posted April 5, 2015 Share Posted April 5, 2015 (edited) I have recently been working on a mod that dynamically attaches scripts to actors, as discussed here. Everything works fine at first, but I started noticing some weird behavior when loading a saved game. I'll try to summarize what I've observed. Under certain circumstances, the activemagiceffect is removed from NPCs and the event OnEffectFinish is called. One example of when this happens is simply when moving far enough away from an NPC. However, moving to an interior cell does not necessarily remove the effect. For example, if the effect is applied to NPCs in Riverwood, and then the player enters a building in the town, deactivates the cloak that applies the activemagiceffect (so it won't be reapplied to NPCs), and exits the building, the NPCs will still have the effect applied to them and active. This behavior is reasonable and, I think, what should be expected. Now, if you enter a building in riverwood, let the game save, load the game, deactivate the cloak, and then exit the building you will notice something else entirely. The effect is no longer applied to the NPCs. At least, checking the NPC using the console shows that the effect is not active (although the spell it is normally attached to is still listed on the NPC, the ActiveMagicEffect is not). However, the event OnEffectFinish is never called. What's more, the script on the effect that was on each NPC is still running! If you have an OnUpdate event, perhaps something simple that just demonstrates that the script is running with a notification, you will see that it still fires. The script's internal state is still preserved, too, as all variables and properties are still set to whatever they were when the game was saved. Also, calls to native functions all seem to fail, and will throw errors that show up in the papyrus logs. But here's where things get really messy: If you reapply the spell to an NPC that currently has such a "phantom" activemagiceffect, then the new instance of the activemagiceffect will share its internal state with the "phantom" instance of the script. Internal variables that have a default setting will instead be set to whatever the "phantom" instance has them set to. If you are using States, then the new instance will also start in the State that the old instance was last in. Also, it seems like both instances can be run by separate threads simultaneously, although I am not 100% certain of this because it is hard to test. Another thing I am fairly certain I have observed in this regard are separate calls to OnUpdate resulting from different timings of registerforsingleupdate. That is, the updates are occuring asychronously, and a call to OnUpdate for one instance of the script does not seem to prevent another call to OnUpdate in the other instance of the script. Dispelling the new instance does not seem to dispel the other, although this could stand further verification as testing it is tricky. The ramifications of this, if I am correct about what is going on, could include a whole host of bugs. At the very least, scripted activemagiceffects that use the OnUpdate event may not be thread safe, and could behave extremely unreliably. Can anyone else verify this behavior? Are there any good workarounds, or do we just need to avoid using activemagiceffects with internal states or scripted OnUpdate events that could be corrupted by this issue? Edited April 5, 2015 by jimkaiseriv Link to comment Share on other sites More sharing options...
Recommended Posts