Jump to content

Are very long scripts a problem?


Recommended Posts

Length of script is irrelevant, its still exactly the same as managing compute/memory/storage resources on mainframes in the 1960s (just add a render pipeline);

 

- Properties and persistent script variables use up limited script memory heap (War of the commonwealth found the actual limit).

 

- Script function calls use the limited compute time (mostly) in between frames.

 

- Non native event registrations load up the event broker.

 

Whether they are in one massive 2000 line script or chunked into 10 scripts of 200 lines each the same resources are consumed. Blocking functions (Utility.Wait), multi-threading and maintenance are good reasons to chunk up a large script.

 

There are no hard rules on this, only experience and performance test observations. People sometimes ask me for advice and when I try to explain they need to cut a bunch of their content as the cost is not worth the envisiaged 'mursive benefit they think I'm mad as apparently mods are supposed to hoover up as much resource as they can and trash save games.

Link to comment
Share on other sites

Length of script is irrelevant, its still exactly the same as managing compute/memory/storage resources on mainframes in the 1960s (just add a render pipeline);

 

- Properties and persistent script variables use up limited script memory heap (War of the commonwealth found the actual limit).

 

- Script function calls use the limited compute time (mostly) in between frames.

 

- Non native event registrations load up the event broker.

 

Whether they are in one massive 2000 line script or chunked into 10 scripts of 200 lines each the same resources are consumed. Blocking functions (Utility.Wait), multi-threading and maintenance are good reasons to chunk up a large script.

 

There are no hard rules on this, only experience and performance test observations. People sometimes ask me for advice and when I try to explain they need to cut a bunch of their content as the cost is not worth the envisiaged 'mursive benefit they think I'm mad as apparently mods are supposed to hoover up as much resource as they can and trash save games.

 

That's some quality information, thanks. If I were to put all of these in one script it would contain 4k lines or more. I should probably err on the side of caution and chunk it up a bit.

Link to comment
Share on other sites

Reasons why I split up my scripts:

 

#1 Separation of Concerns: Each script has a narrow, well defined scope of function/action. The script caters to this function/action only, and does absolutely nothing else.

#2 Maintainability: Scripts made according to #1 will be easier to maintain than a "god script" that does "everything" with 30k lines of code.

#3 Reusability: If you have a generic script that applies matswaps to references but does absolutely nothing else, you can reuse that script whenever you want to apply matswaps to references - even in other mods.

#4 Performance: Generally, a script can run only one thread at a time. You can run one thread each on multiple instances of the same script though. Papyrus can go really really fast if you do this, but it's tricky.

Link to comment
Share on other sites

Reasons why I split up my scripts:

 

#1 Separation of Concerns: Each script has a narrow, well defined scope of function/action. The script caters to this function/action only, and does absolutely nothing else.

#2 Maintainability: Scripts made according to #1 will be easier to maintain than a "god script" that does "everything" with 30k lines of code.

#3 Reusability: If you have a generic script that applies matswaps to references but does absolutely nothing else, you can reuse that script whenever you want to apply matswaps to references - even in other mods.

#4 Performance: Generally, a script can run only one thread at a time. You can run one thread each on multiple instances of the same script though. Papyrus can go really really fast if you do this, but it's tricky.

 

Makes sense. One thing I still don't understand though is how threads are allocated to global function calls, with them not having a Self. Will the engine still notice and usher them all into the same thread if the processes are concurrent and from the same script?

Link to comment
Share on other sites

Consider each script instance as one thread of execution.

 

https://www.creationkit.com/index.php?title=Threading_Notes_(Papyrus)

 

A global script which contains only global functions will be one thread, the "self" is probably a NUL ScriptObject as it cant hold any persistent variables or event registrations.

Link to comment
Share on other sites

Consider each script instance as one thread of execution.

 

https://www.creationkit.com/index.php?title=Threading_Notes_(Papyrus)

 

A global script which contains only global functions will be one thread, the "self" is probably a NUL ScriptObject as it cant hold any persistent variables or event registrations.

Very useful information, never took the time to understand threading, glad i did now.

PS

Can you clear something for me about latent functions ?

if i do something like this:

bool myBool = false
myBool = Myquest.Start()
If myBool
  ;do something
EndIf

Does the script wait for the start() to return before checking "if true/false" or myBool will be "false" if the quest doesn't start in time ?

I've seen people using a while loop to start a quest and i don't feel confortable with it:

While !MyQuest.isRunning()
   utility.wait(0.1)
   MyQuest.Start()
EndWhile
Edited by lee3310
Link to comment
Share on other sites

No a script will not wait for an IF evaluation to be true, it is a point-in-time test.

 

Unbounded while loops are pure filth, really nasty as they block the whole script and constantly consume valuable script execution ticks in that case every ~6 frames and could do in perpetuity as they are Unbounded. Use an event, either standard system or create a custom event or start a real time timer for a regular test. In this case there are several system events that can be used as elegant triggers;

Self.RegisterForRemoteEvent(myQuest, "OnQuestInit") OR
Self.RegisterForRemoteEvent(myQuest, "OnStageSet") ; if the quest actually sets stages, some dont

Which could look like this;

 

If (myQuest.IsRunning() == False) 
   Self.RegisterForRemoteEvent(myQuest, "OnQuestInit")
Else
   DomyQuestRunningStuff()
EndIf

Event Quest.OnStageSet(Quest akSender)
   If (akSender == myQuest)
      Self.UnRegisterForRemoteEvent(myQuest, "OnQuestInit")
      DomyQuestRunningStuff()
   EndIf
EndEvent

Function DomyQuestRunningStuff()
   ;stuff
EndFunction
Link to comment
Share on other sites

 

No a script will not wait for an IF evaluation to be true, it is a point-in-time test.

 

Unbounded while loops are pure filth, really nasty as they block the whole script and constantly consume valuable script execution ticks in that case every ~6 frames and could do in perpetuity as they are Unbounded. Use an event, either standard system or create a custom event or start a real time timer for a regular test. In this case there are several system events that can be used as elegant triggers;

Self.RegisterForRemoteEvent(myQuest, "OnQuestInit") OR
Self.RegisterForRemoteEvent(myQuest, "OnStageSet") ; if the quest actually sets stages, some dont

Which could look like this;

 

If (myQuest.IsRunning() == False) 
   Self.RegisterForRemoteEvent(myQuest, "OnQuestInit")
Else
   DomyQuestRunningStuff()
EndIf

Event Quest.OnStageSet(Quest akSender)
   If (akSender == myQuest)
      Self.UnRegisterForRemoteEvent(myQuest, "OnQuestInit")
      DomyQuestRunningStuff()
   EndIf
EndEvent

Function DomyQuestRunningStuff()
   ;stuff
EndFunction

 

Much better thank you. I just have to split my function in two and call the second part based on IsRunning() result.

It's a bit tricky when the function which starts the quest has parameters (you have to use external declarations)

Edited by lee3310
Link to comment
Share on other sites

  • Recently Browsing   0 members

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