[v1.7.0+] Negative Effect Timeout Cleanup
Posted: Tue Jul 12, 2022 11:12 pm
So it finally happened to me — a temporary effect that didn't expire when its duration fell below zero. (In my case it was triggered by another error, about which more elsewhere.
) At least now that I have a viable test case to work with, I can take a stab at fixing it, or at least cleaning up behind it. What I've got so far is my new (and rather clumsily named) Negative Effect Timeout Cleanup addon
So here's the basics of what's happening: The :setEffect() method sets a temporary "we're in the middle of setting up this effect" flag on an effect while it's in the process of adding it to an actor, and clears that flag when the effect is in place and ready to go. The :removeEffect() method checks for that flag and, if it's present, delays removing the effect until the flag is cleared. (I guess there was an issue with effects being removed out from under themselves?) Problem is, if a stack trace happens inside :setEffect(), that "setting-up" flag never gets cleared, and thus :removeEffect() will never remove the effect.
The fix I'm going with for this pass is in the related :timedEffects() method, which is called once per turn to decrease effect countdowns and handle their actual, well, effects. My theory is that it shouldn't be possible for us to be in the middle of setting up an effect at that point, so any "setting up this effect" flags we may find lying around at that point must be spurious and thus should be cleared.
And since this is exactly the sort of addon that people will likely want to add to a savefile retroactively, I'll go ahead and take a stab below at a FAQ on how to do so that I can link back to from the Steam page.
[And since this is pretty explicitly a bugfix addon, I'm hesitant to include it in ZOmnibus, since we'd have to claw it back out if the bug is fixed later.]
[Implementation notes:]

So here's the basics of what's happening: The :setEffect() method sets a temporary "we're in the middle of setting up this effect" flag on an effect while it's in the process of adding it to an actor, and clears that flag when the effect is in place and ready to go. The :removeEffect() method checks for that flag and, if it's present, delays removing the effect until the flag is cleared. (I guess there was an issue with effects being removed out from under themselves?) Problem is, if a stack trace happens inside :setEffect(), that "setting-up" flag never gets cleared, and thus :removeEffect() will never remove the effect.
The fix I'm going with for this pass is in the related :timedEffects() method, which is called once per turn to decrease effect countdowns and handle their actual, well, effects. My theory is that it shouldn't be possible for us to be in the middle of setting up an effect at that point, so any "setting up this effect" flags we may find lying around at that point must be spurious and thus should be cleared.
And since this is exactly the sort of addon that people will likely want to add to a savefile retroactively, I'll go ahead and take a stab below at a FAQ on how to do so that I can link back to from the Steam page.
[And since this is pretty explicitly a bugfix addon, I'm hesitant to include it in ZOmnibus, since we'd have to claw it back out if the bug is fixed later.]
[Implementation notes:]
Code: Select all
Superload:
mod.class.Actor:
timedEffects() [to clear stuck __setting_up flags]