sornan Posted August 24, 2020 Share Posted August 24, 2020 (edited) Hey again.. I could use some help here on this Did some web searching, and could not find an answer, and really ran into an unexpected wall hereI finally got my first main quest script fleshed out, uses a SingleUpdate loop that has worked great. I put in a new script, in the same quest, that once again uses SingleUpdate, and it is causing the original script to actually run multiple times within the SingleUpdate event. Then I tried a While loop in the OnInit Event in the second script, with a Utility.Wait 3.0 per loop, and even worse, the loop worked fine but it literally stopped the functionality of the first main script. Here is a basic code example : Scriptname GaladrielDream extends Quest ;Register for OnUpdate to start looping code area Event OnInit() ;Before we can use OnUpdate() we must register. RegisterForSingleUpdate(1.0) EndEvent Event OnUpdate() ;Do a ton of stuff, works great.. ;keep updating RegisterForSingleUpdate(1.0) EndEvent ;Second looping script added Scriptname CJA_Phase1_Script1 extends Quest ;Register for OnUpdate to start looping code area Event OnInit() ;Before we can use OnUpdate() we must register. ;adjust timing slightly on each new register so checks in various scripts do not execute at the same time RegisterForSingleUpdate(1.3) EndEvent Event OnUpdate() ;Do stuff.. ;keep updating RegisterForSingleUpdate(1.0) ;THIS NEW SCRIPT CAUSES THE SINGLEUPDATE AREA IN THE FIRST SCRIPT TO RUN MULTIPLE TIMES EndEvent ;SECOND ATTEMPT ;So the first try failed, I then tried a While loop in the OnInit in the second script Scriptname CJA_Phase1_Script1 extends Quest Int TestA = 0 ;TEST Event OnInit() While (TestA < 100) TestA = (TestA + 1) Debug.Notification("Var is less than 100") Utility.Wait(3.0) EndWhile EndEvent ;The debug text shows fine, and yet the While loop totally kills the functionality of the first script, nothing else seems to work but the loop ;I finally just combined the code into one SingleUpdate event in one script, and it all works fine.. I'm trying to figure out what is going on here.. does this game not support multiple looping scripts (potentially with delays) happening at one time? And how can that be possible, the checks in my looping scripts are normally one liner variable checks to be performance friendly.. and yet in Oblivion and Arma 3 I would have friggin 10 looping scripts running at once without anything strange going on.. So I decided for now just to combine the code into one script, and it's all fine, but I really could use some input on this. I can't believe that this game would only support one looping script running at a time. Any help appreciated, I'm just stumped at this point Edited August 24, 2020 by sornan Link to comment Share on other sites More sharing options...
foamyesque Posted August 24, 2020 Share Posted August 24, 2020 (edited) You can have as many loops as you like; the issue is that you put the loop in the OnInit block. As long as an OnInit block is running on an object, nothing else except other OnInit blocks can run on that object. It's to prevent races. Since your loop takes (a minimum of) 300 seconds it blocks everything else from running until that time is up. This behaviour is why it's generally recommended to keep OnInit blocks as small and fast as reasonably practical. OnUpdate events are shared amongst all scripts attached to the same object, which is why both quest scripts trigger it. Edited August 24, 2020 by foamyesque Link to comment Share on other sites More sharing options...
sornan Posted August 24, 2020 Author Share Posted August 24, 2020 Thanks foamyesque That information is helpful. So basically, with SingleUpdate, in order to have 2 or more scripts safely using the loop, they have to be attached to different objects - like in my case, I put in those two scripts under the same quest, and so both updates would trigger each other - so to have multiple quest scripts working safely with SingleUpdate, I would need each script in a separate quest.. I think I got that right, please let me know if I'm still off on that. Lastly, on the While loops, is there any kind of generic Event that can be used to just outright run a While - loop upon a script starting? I did a search through the events, and didn't see anything that would work to just kick off some code without a real "event" happening once a script starts. And thanks again for the help, and sorry about the not-so-cheery topic post, I was pretty discouraged last night after *thinking* I had passed a milestone in things.. and then things start breaking again.. Cheers! :) Link to comment Share on other sites More sharing options...
foamyesque Posted August 25, 2020 Share Posted August 25, 2020 There's only two ways for a script to be started: Through an ingame-generated event of whatever sort, or through an external function call from some other, already started, script. Ultimately that means sooner or later every script is started by an engine event of some sort. Generally the pattern I use for initializing a script is to define as many things as I can in the property and variable declarations. The OnInit() block handles things like declaring arrays, or error-checking the property settings. Any more calculation intensive material -- sorting an array, formlist manipulation, other frame-linked function calls, etc -- I offload to an OnUpdate event via a short RegisterForSingleUpdate() call at the end of the OnInit() block. The OnUpdate event is split into a 'run the first time' and 'run every other time' if necessary, by states. That way I can precisely control when the rest of the script 'turns on' and make sure it only does so once all the data is of the kind and type it expects. Link to comment Share on other sites More sharing options...
sornan Posted August 25, 2020 Author Share Posted August 25, 2020 (edited) I see. So essentially, for running looping 'main scripts' that would often be quest scripts, OnUpdate is pretty much all there is for just kicking off a potentially big looping script that handles a variety of things going on. I'm good with that, and just have to accept that only one script per quest can do that. I've had good success with using basic variables in the scripts, along with globals, but I'm not feeling ready to even look at Arrays yet, as the scripting system is quite different than what I'm used to, and maybe I won't ever need to use arrays anyhow. Armed Assault 3 had a pretty basic approach to arrays, and even multi-dimensional array usage was pretty straightforward. On the other hand, Armed Assault 3 is a game somewhat crafted to cater to modding, and even in Oblivion I don't think I ever even tried to look at things like arrays (does it have them?). /Edit I do have one question Why are we able to initiate local variables in a script in the 'empty' areas at script start, and apparently that is safe - indicating that the script will never re-run those areas outside of Events, yet we have OnInit Event, which would seem to me to do the same thing? I mean, is it safe to keep initiating local variables in a script outside of the Events, or is it maybe better to just regularly make an OnInit Event and initialize everything there, including local variables (provided they are still accessible by the rest of the code and other events in the script). Thanks for your patience with my questions.. Edited August 25, 2020 by sornan Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 25, 2020 Share Posted August 25, 2020 Local variables must be declared and defined prior to their use. If inside an event or function then that variable is only usable inside that event or function after the point of defining. If in the empty state, it can be used throughout the script. For example: NOTE: This is done for example sake of local variable declaration and definition. This is not intended to be used as an example for anything else. Int myNum = 21 Int answer Event OnInit() answer = myNum Debug.Notification("U.S. Drinking age is "+answer) ; will display on screen "U.S. Drinking age is 21" RegisterForSingleUpdate(0.25) EndEvent Event OnUpdate() Int myMult = 2 answer = myNum * myMult Debug.Notification("The answer to life and everything is "+answer) ; will display on screen "The answer to life and everything is 42" EndEvent The variable myNum can be used inside both events due to having been declared and defined in the empty state.The variable myMult can only be used inside OnUpdate due to having been declared and defined there.The variable answer can be used inside both events due to having been declared in the empty state, yet it provides different values due to being assigned separately in each event. -- However it would be better to used separate variables declared and defined inside each event. It is always best to declare and define your local variables just before you need them. Only declare and optionally define them in the empty state if they need to be used within multiple events and / or functions. Link to comment Share on other sites More sharing options...
sornan Posted August 26, 2020 Author Share Posted August 26, 2020 (edited) Thanks IsharaMeradin That helps quite a bit. Of course there are complexities in declaring local variables within an OnUpdate Event, because the loops will just reset the values at the start. But generally, I get what you are saying, in particular for non-looping events - where even a While loop inside the event can access the declared variables in the event. I didn't know that Debug.Notification could show variable content, I just copied and pasted that for reference, great to know for testing :smile: I am curious why RegisterForSingleUpdate has to be in an OnInit event, rather than just being able to declare it in the 'empty' area at the top, but it probably is just the way the command is setup to function. Thanks! Edited August 26, 2020 by sornan Link to comment Share on other sites More sharing options...
IsharaMeradin Posted August 26, 2020 Share Posted August 26, 2020 All function calls have to take place inside another event or function. The compiler will not compile a script that has a function call in the empty state. Papyrus doesn't run down the script looking for something it can run and then start over at the top. Rather if the object holding it is loaded or persistent the attached script(s) will sit in memory listening for the game engine to send an event trigger or a script call to one of its functions. This is why it is important to test scripted stuff on new games or saves that have not seen the mod. A previous version of the script could be stored in the save file and take precedence over any changes made. Link to comment Share on other sites More sharing options...
maxarturo Posted August 26, 2020 Share Posted August 26, 2020 "This is why it is important to test scripted stuff on new games or saves that have not seen the mod. A previous version of the script could be stored in the save file and take precedence over any changes made." I just want to agree with IsharaMeradin and add an example. In my mod's last update, in the main boss battle, i tweak a few things and i added a few 'Fail Safes' to ensure stability of this heavy scripted scene on weaker systems. The first thing i did was to replace an "xMarker" with an "xMarkerHeading", move back a little the "xMarkerHeading" and change the bosse's "PathToReference()" speed from '1.0' to '0.9'. Then i went in game with the save file i was testing version 1.1 of the mod, the save was made just before entering that cell. The 'start scene' didn't play correctly, and Echidna (the main boss) was lying on the floor just like she was having a STROKE or a HEART ATTACK or an ALLERGIC SHOCK REACTION !!!!!!!. I've never seen that before... it was hilarious !!!, i couldn't for the life of me stop laughing !!!!..... And all of that just from 2 simple changes. Link to comment Share on other sites More sharing options...
sornan Posted August 26, 2020 Author Share Posted August 26, 2020 All function calls have to take place inside another event or function. The compiler will not compile a script that has a function call in the empty state. Papyrus doesn't run down the script looking for something it can run and then start over at the top. Rather if the object holding it is loaded or persistent the attached script(s) will sit in memory listening for the game engine to send an event trigger or a script call to one of its functions. This is why it is important to test scripted stuff on new games or saves that have not seen the mod. A previous version of the script could be stored in the save file and take precedence over any changes made. Thanks for clarifying that, makes sense about the usage of the Oninit event for OnUpdate now. Gotcha on the way the scripts function, basically like the script is pre-processed, and the events then just wait for their activation. The save games, I do still rely often on saves within the mod content, but am aware of the possibility of something breaking due to this, so it is factored in when an issue happens during testing. Ironically, through probably 100 or more tests so far, I have only had problems with my usage of the CK and coding, a save game issue hasn't happened.. but I am sure it will sooner or later :) "This is why it is important to test scripted stuff on new games or saves that have not seen the mod. A previous version of the script could be stored in the save file and take precedence over any changes made." I just want to agree with IsharaMeradin and add an example. In my mod's last update, in the main boss battle, i tweak a few things and i added a few 'Fail Safes' to ensure stability of this heavy scripted scene on weaker systems. The first thing i did was to replace an "xMarker" with an "xMarkerHeading", move back a little the "xMarkerHeading" and change the bosse's "PathToReference()" speed from '1.0' to '0.9'. Then i went in game with the save file i was testing version 1.1 of the mod, the save was made just before entering that cell. The 'start scene' didn't play correctly, and Echidna (the main boss) was lying on the floor just like she was having a STROKE or a HEART ATTACK or an ALLERGIC SHOCK REACTION !!!!!!!. I've never seen that before... it was hilarious !!!, i couldn't for the life of me stop laughing !!!!..... And all of that just from 2 simple changes. I'm sorry for Echidna.. not exactly the definition of an honorable death in battle right.. :p I do hear you though, I use the saves because they are *normally* reliable, but also when an issue comes up I am aware that the save game could be the problem. I've thought about advancing quest stages manually and whatnot while testing on a clean save, trouble is part of the time a bunch of other stuff is missing still, trying to reproduce everything manually to jump ahead in the quest would probably be more trouble than risking using existing saves. Link to comment Share on other sites More sharing options...
Recommended Posts