Skyrim

PART I: Concepts.
_________________

Much has been said about "script heavy" mods and how the can break your game. But over the years, the notion that scripts can break your game has become less and less of an understood phenomenon, and more of a creepy boogeyman to scare children away from using scripted mods.

I'm here to shed some light on this matter, not because I'm an expert nor because "I know it all", but instead, because I've investigated this phenomenon, I've witnessed how it works with my own eyes, and I've learnt to take measures on how to solve it most of the times.
This article may be of beginner level to some, but I intend it both, to help beginner modders learn something, and to attempt to make normal users undersand a bit more about why their game could be "broken" and why it's not because of "script heavy mods' fault".

First of all I have to say one very important thing: THERE ARE NO SCRIPT-HEAVY MODS.
-"But Myst, everyone knows if you install mods with scripts, you can break your game"
Lies. Scripts won't break your game. Bad coding, however, can, and it poses a real danger, but that's not something that happens because of "scripts being scripts", it happens because a modder makes a mistake and publishes a mod with bad coding.

Second, we should clarify what does people understand by "breaking one's game".
Because this notion may seem generic and common, but it may be different for everyone. Some people says it relates to having frequent CTDs, while others, such as myself think it relates to when the game's scripts seemingly stop working and you can't do anything because scripts dont do what they're supposed to do.
I have experienced this kind of "broken game" myself as well, and I also fought to understand the reasons for it, and ultimately, fix them.
Script lag, is one thing, but CTDs and broken quests are a completely different one, and it's usually related to stuff such as a bad load order, mod incompatibilities, corrupt assets (IE missing textures or broken nifs) or bad graphic settings but neither of these has anything to do with scripting.
Alternatively, some scripts can cause CTDs, but that's a rare thing and it's usually related to other types of bad coding which I wont refer to on this article.

Third, there is another misconception on what a "script heavy mod" even is. Because it can be

  • A mod with many scripts.
  • A mod with LONG scripts.
  • A mod with complex scripts that interact with many things
  • A mod with scripts that never stop running in the background

And here's the shocker, because NONE of the above constitutes ANY kind of danger to the game.

A friend developed an entire mod to test the effects of scripts on the game and try to pinpoint an exact cause of script issues, it was designed to overload the game in every possible way as described by the "script heavy" myth, and his results concluded that the game can candle thousands and thousands of instances of scripts simultaneously in the background, and keep running without even coming close such a thing a s "limit". The mod was designed to push Skyrim's script engine's limits beyond what any combination of mods can ever achieve.

PART II: How It Happens
________________________

What was found after such testing, however, is that there is a situation that DOES exist, and can be mistaken for a "broken game" because in practice, it is.
I will not describe every possible case of "bad code", because I'm certain there's more than one screw up that can cause game issues, but I will talk about one of the most frequent ones which is by far, one, if not the most common reason of script issues.

And now, I'm referring to something I call "script saturation" although I'm not sure if that's the correct term.
This phenomenon, occurs when the game is receiving lots and lots of simultaneous script calls per second.
As a result, a chain of events begins to occur.
  • First,you'll notice the game can start lagging in terms of scripted events. If something was supposed to happen when you get hit, you'll notice it happens later, if you use a scripted spell, the effect will also come with a delay. This lag can be something tolerable, or it can be massive and you end up seeing the effects of a script, as far as 5 minutes later, or more.
  • Second, if you have enabled the log in your Skyrim.ini, you'll notice the existence of the infamous stack dumps. Stack dumps, arent a problem per-se, but they are warning you of the current script saturation you're experiencing.
  • Script saturation, in the internal mechanics of the game, means you're getting too many script calls and the game isn't capable of answering them all in time, so it stores pendant calls for the next frame in hope it can finish in time, so as described by the wiki (somewhere I can't recall), the game delays the execution of scripts. The visual result was evident since you started seeing script lag occur and stuff happening seconds, to minutes after they were supposed to.

PART III: Why it Happens - Section A): Fundaments of Script Lag
________________________

-"I knew it!, I knew script heavy mods existed, you're just trying to confuse me!"
Technically, a form of "script heavy" mod can exist, but I just call that BAD CODE.
See, the thing is, it doesnt happen because "a mod has many scripts" or because "the scripts run in the background" or "are too long". It doesnt happen either because "you have too many mods" or "you combined more than 2 or 3 script-heavy mods in one install".
It happens EXCLUSIVELY for the action of a single, lone script, which can come from anywhere, at any time.
Any script can have bad coding, and size doesnt matter.

If you want an example, here is one:
Spoiler:  
Show
ScriptName BadEffectScript Extends ActiveMagicEffect

Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)
    Utility.Wait(5.0)
EndEvent

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
    Utility.Wait(5.0)
EndEvent


The pevious script, has only 2 events, and does absolutely nothing in practice. But what it does do, is cause an event to get locked on processing as soon as it arrives.
Now, during a battle, a concentration spell can spam these events dozens of times each frame, and the longer such concentration spell is held on the bearer of this script, the more script calls that begin to accumulate on them, until at a given moment, the barrier will be breached and your papyrus log will generate a stack dump.
When that happens, if you were expecting something to happen with the script, say a shader apply, you'd notice shaders begin being applied later.
And this is how a single script with 2 spammy events and no precaution, can generate script spam and slow down your script engine.
Notice it's not long, it's not complex, it doesnt even do anything it just spams events.
The probem is that the more events that get spammed, the more likely the game gets saturated, and other scripted mods will suffer the script lag as well.

PART III: Why it Happens - Section B): A Broken Game
______________________

The game, can normally recover from these kinds of situations, after all no mod is going to have a concentration spell casted on an actor during the entire game... right?...
Wrong.
Some mods, use mechanics that do apply constant effects on the player, ALL the time. And if you have a mod that's set to respond to these events, if it's not set correctly, there's a chance it will get saturated.
The first part was correct, the game DOES try to recover from stressful scripting situations, and it does this by simply finishing answering all the script calls untill the demand is back to what it can answer on a single frame, AKA a relaxed environment.
It's simple, the stress rises up, the game deals with it as best as it can, then the stress ends and the engine can relax again.

But what if it never relaxes?

This is when the real danger of event spammers comes into play.

It happens when you have a stressful situation that generates enough script calls to saturate the engine, and you dont ever get to the moment when it finishes answering them all.
I dont know the exact number, but as a mental exercise, lets say the game can answer 100 script calls per second, from a single concentration magic effect.
Now, picture that you have a combination of mods, that allows an event spammer as described above, coupled with a stressful situation, say a dragon, 2 companions and 6 mages.
Suddenly, you're no longer receiving 100 script calls or less per second but 400 instead.
The game will queue 300 to be answered on the next time, but when that time comes, we will get another 400
By the third time it checks, you will be getting a total sum of 900 delayed calls because it can only answer 100 each time.
And the lower your framerate, the less actual execution time the script engine has to catch up with the increasing demand.

Now imagine the "battle" never ends, and you get this eternal event spam.
You're never ever going to see scripts working again because the lag is infinite.
This is close to what happens when you have an event spammer mod combined with a mod that creates a concentration, or cloak effect, being permanently applied to the player, since more than a few mods apply unseen effects on the player.
This is the reason why scripts stop working and people say their game is "broken".

PART IV. How to Fix It
________________________

The solution, for mod makers, is simple, for mod users, not so much as they have yet to learn to identify a troublesome mod and either fix it or remove it.
But for modders, it begins by knowing the first rule, which is: BEWARE of event spammers.
Try not to use those kinds of events at all, avoid effects that cause repeated calls such as cloaks or concentration type effects if possible, but if you absolutely MUST use those kinds of events/effects, you should always use an EVENT FILTER, like this:
Spoiler:  
Show
ScriptName BadEffectScript Extends ActiveMagicEffect

;;===========================;;
Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)
    GoToState("Busy")
    Utility.Wait(5.0)
    GoToState("")
EndEvent

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
    GoToState("Busy")
    Utility.Wait(5.0)
    GoToState("")
EndEvent

;;===========================;;
State Busy

Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)
EndEvent

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
EndEvent

EndState
;;===========================;;

The above example is a State filter, and it will ensure only one event is processed at a time, and when it's done, the gate will be opened for another event.

Alternatively, a Bool filter also works
Spoiler:  
Show
ScriptName BadEffectScript Extends ActiveMagicEffect

Bool BusyMagic = False
Bool BusyHit = False

;;===========================;;
Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)
    If BusyMagic == False
        BusyMagic = True
        Utility.Wait(5.0)
        BusyMagic = False
    EndIf
EndEvent

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
    If BusyHit == False
        BusyHit = True
        Utility.Wait(5.0)
        BusyHit = False
    EndIf
EndEvent

;;===========================;;

The second example is not as effective as the first one since it still has code inside, but it will reduce script spam.

Note that none of these methods is flawless. Even when using them, mods are still likely to get a stack dump or two every once in a while, but by reducing their capacity to spam, you will ensure that the game's load can be overcome more than 90% of the times.

So you see, scripts are not evil, but we have to be careful about how we design our mods because it's very easy to screw up and end up regretting it later. Most people never bothers to understand the mechanic of this phenomenon, and when their game malfunctions, they look for the causes of it on myths such as "scripts being evil" when it's not about having many scripts, or complicated scripting. A single mod is more than capable of "breaking" one's game under certain circumstances.

Article information

Added on

Edited on

Written by

Myst42

11 comments

  1. Baller64
    Baller64
    • member
    • 0 kudos
    Just asking if 2079 scripts is too much for a game with 62 mods and 53 plugins that have maybe 1200 max
  2. spyder33
    spyder33
    • premium
    • 3 kudos
    So does that apply to every instance of Utility.Wait()  most of the scripts i open dont have this ? 
    1. Myst42
      Myst42
      • premium
      • 536 kudos
      The Wait() function is only meant as an example.
      The main deal about it is that it "highjacks" a script thread, so to speak. In other words, it keeps the system busy counting miliseconds while the Wait goes on.
      It could be any function or any script, every function takes time and processing power to run, the longer the script, and the more functions it has, the more miliseconds you add to the processing time. it looks almost instant to us, but the system does require its time to run through code lines.

      As long as a script is running, the system is occupied with it, and it adds one more thing for it to do.
      The dangers of script saturation lie in the fact that the system receives so many script calls that it gets busy answering all of them, up to a point where the entire engine slows down until it finishes answering all the calls.

      Wait is simpler because i'm not really doing anything, but it's enough to keep the system busy on a running script for 5 seconds in that example. The script will only disappear, and release the engine once those 5 seconds are over.
    2. Excinerus
      Excinerus
      • premium
      • 128 kudos
      Wait() does what it says, wait, the system isn't counting time during that, wait(5) kinda sets an appointment in 5 seconds and the engine does something else while keeping the stack until the time comes. now even that can kill the engine if you multiply it by a big enough number.

      Wait() is the correct way to wait for a typical asynchronous call and it's usually for a fraction of a second, for example 
      ObjectReference Cheese = Player.PlaceAtMe(CheeseWheel01)
      Utility.Wait(0.1) ; if we don't wait here the engine might attempt to set the scale before the cheesewheel spawns
      Cheese.SetScale(10)

      however you wouldn't call it at the start of an effect to have it do some thing after 5 seconds, for that you do 

      KeyWord property k auto
      ObjectReference caster

      Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)
         if (akEffect.HasKeyWord(k))
            caster = akCaster
            RegisterForSingleUpdate(5)
         endif
      EndEvent

      Event OnUpdate()
         DoTheThing( caster )
      EndEvent 

      This way the engine actually lets go of the stack while it's waiting,  it's like the difference between being told to remember a phone number until when asked for it in 5 minutes and writing it down till the time comes


      What to watch for here is that it's a OnMagicEffectApply Event,  meaning that it will fire for each Magic effect in an effect list, for every enchantment, explosion, Potion, Poison, Food and Spell, for every tick on a concentration spell, and every time an effect is activated on an constant ability.

      So a good implementation would take this into account,  make its best filtering,  and set up some sort of flood control with states.
  3. blankCo
    blankCo
    • member
    • 0 kudos
    Frozen electrocuted combustion is one of those script spammer..
  4. cascadahk
    cascadahk
    • member
    • 0 kudos
    Very clear and detail explanation!
    I think most of the people avoid script mods because they afraid the save will be corrupted when they remove some of the script included mods in mid-game
  5. Whitified
    Whitified
    • member
    • 4 kudos
    So um........ which mods do we avoid...?
    1. Myst42
      Myst42
      • premium
      • 536 kudos
      This wasnt exactly about "which mods to avoid" but more about letting go of the fear that using scripts is what "breaks games". But good question nonetheless.

      If you want to know exactly what mods to avoid, I can't tell you that, because I dont know them all, and have only encountered a few. Biggest example that comes to my mind is Immersive Beds. The way it's built (according to my friend, since I didn't actually analize it personally), ensures that script calls accumulate and the engine starts to malfunction, something I saw on my own game. Using that mod, experiencing issues, and later changing to Go To Bed, which works without any issues, was one of the first things that I had to do upon learning about script mechanics.
      Otherwise, if you want to know about mods which are "demanding" then, you should know some of the most popular ones are actually demanding in the sense they rely on script calls and concentration spells applied constantly on the player. Some examples are XPMSE, FNIS and SOS, but unfortunately, these are almost impossible to avoid, because they're practically the base of every well modded Skyrim. None of these mods, however has anything "bad" about it. They are demanding and can slow the engine, but they wont "break games", only true "bad code" can do such a thing.

      Finally, mods do all sorts of things. This article is about one specific deal: Mods that have scripting.
      I tried to explain and establish why scripting is not evil and rarely does any real damage except if A): The code causes event saturation, and/or B): A mod has actual bad coding.
      Other areas of mods include texture and model replacers and of course, esm/esp plugins which all have wonders and dangers of their own. High Res textures, can cause frame drops, which in time leads to reduced script execution time, and slowing the engine, and that is also something to keep in mind when picking up mods.
  6. qwertypol012
    qwertypol012
    • supporter
    • 74 kudos
    Thanks for the article

    If you still remember me, i was the one asking in the posts section of your weapon speed fix modpage. I came to understand that it's actually not about the "script-heaviness" (hell, i have never been using this term after i realized a bit about the nature of scripting) or even "script-intensiveness" (this term, at least for me and for some people, still makes a bit more sense than the previous term because naturally "bad" scripting will cause the script to take more resources that what it actually needs, so lately i've been using it). So, i think you can help people by spreading a correct term as opposed of "script-heaviness" in which (for me) it doesn't really make any sense (though it probably do for some people, depends on the reason on why that term is being used).

    In my assumption, many people use that term based on "how the script affect your game's performance". They see some scripted mods making their game lagging, making quests glitchy or buggy, etc so they conclude that such mods are "script-heavy" (by "heavy", means that it's "heavy" for their PC/system by causing lagging, freezing, etc). I purely see it as a matter of memory and hardware capability, and also Skyrim LE's limitation itself with its own seemingly old engine (couldn't remember the name, but many people kept complaining about it) and/or its Papyrus scripting language itself (based on some people mentioning that it's a rather fragile programming language, though i have no clue about it since i'm not a programming person myself). I don't see how scripts can break your game, because CTD itself has many causes; and based on my observation, it's mostly caused by memory problem and other technical stuff, rather than caused by bad scripts. Based on my experience, the best scripts can mess my game is by causing performance lag (ie. script lag), quest stages won't advance (or quests just stopped working), unwanted NPCs behavior (NPCs whom affected by the script), and any other technical issues like that. It hasn't even taken any account about mod incompatibility (which also causes a lot of further problems). As far as i can remember, i never experienced CTD due to bad scripts. I even tried my edited scripted mod which apparently badly written and the game still worked fine, though the scripts keep spamming update almost nonstop (i have fixed it in the recent version though).

    What i can conclude is, at least for now, scripts shouldn't crash your game, but badly-written scripts can still "break" your game in some ways. By "breaking", it means causing some functions in your game stopped working or working with unintended behaviors or behaving in a wrong way, such as quest failures, NPC behavior bugs, some gameplay bugs, etc; which can be further worsened via mod incompatibility. And it can, based on my and many people experience, disrupt your game performance (ie. the infamous "script lag") which can be mitigated by editing your game's .ini PAPYRUS settings and/or upgrading your CPU, though the limitation will still likely persist at some degree due to the game's own inherent limitation.

    Just want to tell my view about this issue. Definitely just a 2 cents from me, since i'm still a greenhorn in papyrus scripting and still have much to learn. So any correction is very welcomed.
    1. Myst42
      Myst42
      • premium
      • 536 kudos
      Np.
      Yeah, I remember your comment.
      You, some others and a few other things too, are the reason I decided to write this. Figured it would come in handy, especially if I just want to link the explanation instead of having to write a long reply to anyone who comes asking,
      By the way you sound, it seems like you might still have some confusion left, but you're on the right track. Learning curve is not something that happens over night.
      Personally, I'd say "script-intensiveness" still sounds a bit weird to me because it's closer to the heavy term, and still leaves me with a taste of something that "causes demand but it's still necessary" and it really isn't. Either the scripts are done properly or they're not. IE an event spammer is "intensive" yeah, but that's cause it's made wrong. Other examples of scripts "consuming more resources that they should" as you say, include weirdly redacted "While" loops that can potentially grow into resource-consuming abominations, but the way I see it, that's an even worse kind of bad code. But anyway, even if I dont particularily like the term, sounds like you may be getting the right concept, which is what matters the most.
      Also scripts barely consume any reasources by themselves according to my friend's testing utilities anyway. What consumes resources, is what they do.
      Scripts lines determine what are they consuming, be it time, graphics, memory etc, and that's more related to the game's performance capabilities rather than the code.

      On a side note, do not ever confuse "updates" with "spam" because the concept difference is abyssmal. Updates, are something programmed and expected, it happens in a linear and chained way. There's only 1 chain updating itself in an ordered way. If you have more instances of the script, sure there'll be more chains, but they're still linked linearly and it's a clockwork mechanism. Event spammers are completely different because they're unexpected, they're not linked, they are completely out of control and they can generate calls exponentially, and this happens for each instance of the spammer you have.

      Finally, on papyrus ini settings, I wont go there since that's another big topic in which I dont have complete understanding. I have followed the advice of people who know better than me for this and managed to set mine to something that runs smoothly. But as I said, it's a long topic, and they're entire threads of technical discussion on this matter. That's is of course, the other big aspect of game health; setting ini parameterers to correct values that match your CPU and memory to optimize performance.
    2. grodwizneo
      grodwizneo
      • member
      • 0 kudos
      Thanks for writing the article. I'm a programmer just getting into PC gaming, and I was wondering why everyone was avoiding scripts. This gives me some good insight. And 'message saturation' seems as good a term for this phenomenon as any.