GMS 2.3+ Change execution order of script assets

Agneum

Member
Is there a way to to make sure one script asset runs before the other? I've tried dragging the script to the top , but that didn't seem to change anything (not to mention there is no easy way to order sort scripts anyways).

The blog post reads:
"scripts are no longer called individually, but are actually all run at the start of the game in the global scope".
 

Agneum

Member
Move the content of the second script into the first script and then delete the second script.
This would be a work-around, but I don't like the idea of merging two separate function files together just because there is a dependency between them. From what it seems, the order of execution seems to be based on on the asset name itself. Would much prefer to have them execute in the order they appear in the tree, or for us to be able to set a priority in the asset browser.


In my case, I run tests at the bottom of each script on a conditional global variable. This would force me to put all tests in the settings script. Which would put the tests in an illogical script, and also bunch them into an incohesive mess.

That or I guess I need to initialize everything using a timer..
 

FrostyCat

Member
Open the yyp and move the script you want to run first to the top of the yyp and save it. *undocumented*
Undocumented as of GMS 2.2, and defective as of GMS 2.3.

You need to stop dispensing this "undocumented ID order" advice right now, as well as its variants like your beloved "resource ID plus offset" hack.
 
Wrap each of the scripts in a function wrapper, then create another script calling them in sequence, thereby specifying the order.
After reading about the changes to scripts and functions, I believe the approach offered by FrostyCat is the most practical way to handle setting a specific order for your scripts/functions now.

Agneum, I'm not sure if this analogy is entirely accurate, but from what I'm gathering in the release notes it seems like they've turned scripts into something like a Class in other programming languages and we can now use them to organize several related functions. For example, I created a new script in my game and called it "Utility." Then I converted several of my helper scripts into functions and added those new functions (ex: "fn_initialize_array", "fn_create_obstacle", etc.) to the newly created "Utility" script so they're all in one place now. I don't know the details of your specific scenario but maybe this idea of "Class" organization could help you keep your scripts organized in this new environment and avoid the "incohesive mess" you were concerned about?
 

samspade

Member
Wrap each of the scripts in a function wrapper, then create another script calling them in sequence, thereby specifying the order.
GML:
function initA() {
    ...
}
GML:
function initB() {
    ...
}
GML:
initA();
initB();
I'm working through this exact issue right now, and I might be missing something, but I don't think this works. If you're declaring these script functions in separate script assets, you have the same issue the order they are run in matters. But the bigger issue is even if the first thing did work, it doesn't give you the same results. Script functions initialized purely inside a script asset are global and unbound. Script functions initialized inside a script function inside a script asset are not. For example the following code will give you an error: Variable <unknown_object>.increase_my_variable(100007, -2147483648) not set before reading it.

GML:
///script asset

function init_func() {

    function increase_my_variable() {
        my_variable += 10;
        show_debug_message(my_variable);
    }

}

init_func();

///object
my_variable = 50;
increase_my_variable();
I could be wrong but I really think there is no way to enforce a specific order of script assets.
 

FrostyCat

Member
I'm working through this exact issue right now, and I might be missing something, but I don't think this works. If you're declaring these script functions in separate script assets, you have the same issue the order they are run in matters. But the bigger issue is even if the first thing did work, it doesn't give you the same results. Script functions initialized purely inside a script asset are global and unbound. Script functions initialized inside a script function inside a script asset are not. For example the following code will give you an error: Variable <unknown_object>.increase_my_variable(100007, -2147483648) not set before reading it.

GML:
///script asset

function init_func() {

    function increase_my_variable() {
        my_variable += 10;
        show_debug_message(my_variable);
    }

}

init_func();

///object
my_variable = 50;
increase_my_variable();
I could be wrong but I really think there is no way to enforce a specific order of script assets.
Your code is wrong. The inner function declaration is accessible only to code inside the outer function, it is not magically transferred to instances that run the outer function.
 

samspade

Member
Your code is wrong. The inner function declaration is accessible only to code inside the outer function, it is not magically transferred to instances that run the outer function.
Wrap each of the scripts in a function wrapper, then create another script calling them in sequence, thereby specifying the order.

Maybe I'm confused then, because I thought I was copying your example. What was it supposed to be?

As a side note, it does appear to be creating them in the scope that it is running as that same code in an instance creates an inner function usable by the instance (with access to the instance's variables) and the code as posted will run without errors if you prefix global before variables in the instance e.g.

GML:
global.my_variable = 50;
global.increase_my_variable();
produces no errors, indicating a named function bound to global scope has been created.
 

FrostyCat

Member
Maybe I'm confused then, because I thought I was copying your example. What was it supposed to be?
You completely took my example out of context.

Assume that foo must be initialized before bar. My suggestion is that the two initializations be placed in their own functions, then called in a third script that runs on startup.
GML:
function init_foo() {
    /* Initialize foo */
}
GML:
function init_bar() {
    /* Initialize bar */
}
GML:
init_foo();
init_bar();
As a side note, it does appear to be creating them in the scope that it is running as that same code in an instance creates an inner function usable by the instance (with access to the instance's variables) and the code as posted will run without errors if you prefix global before variables in the instance e.g.

GML:
global.my_variable = 50;
global.increase_my_variable();
produces no errors, indicating a named function bound to global scope has been created.
That's a direct consequence of the global scope binding phenomenon you observed earlier on. I may have mis-predicted the actual accessibility of increase_my_variable, but that still doesn't make your example right.

Script functions declared at the global level have no built-in self, but get that identity whenever it is called. Methods carry their own self, and work off that bound identity no matter where it is taken. Your increase_my_variable is an example of the first kind by the virtue of it being declared using the named function syntax.

This is why I do not use the named function syntax (i.e. function NAME(...) { ... }) for anything other than declaring script functions at the top level. Everything else I use the anonymous syntax (i.e. NAME = function(...) { ... }).
 

Psycho-Male

Member
Open the yyp and move the script you want to run first to the top of the yyp and save it. *undocumented*
Saved my ass in quickest way possible, I hate putting everything in function just to initialize some variables in correct order, it's just messy. Thank you very much!
Documented ways are usually not practical in rare cases like this so I often find myself modifying .yy files.
 

TsukaYuriko

☄️
Forum Staff
Moderator
Often modifying .yy files is the primary cause of having to often modify .yy files... ;) That should be the absolute last option on your list.

The quickest way is not always the best way, and especially not always the proper way. If your game's primary support beams are relying on undocumented functionality - which, as evident by this topic, does tend to break sooner or later! - then you have the equivalent of a jello foundation. You're essentially setting yourself up for problems in the future, rather than doing things properly once and then being done with it.


With that said, this is not a rare case. Specifying the execution order is one of the most fundamental things, especially in GM, what with it literally having three separate Step events with this being the sole purpose.
 

gnysek

Member
Yeah, in 2.3 they definitely changed script order to random. You can notice that especially after importing some assets - imported scripts gets random positions between another in .yyp file even if they are inside same group.

It may sound as a illogical behaviour, since 2.3 also introduced a more flexible way of defining global variables outside of functions, but because scripts will be ordered randomly now - you can't use functions from scripts other than current to define things to prevent crashing game on start. I'm nearly sure it's caused by sorting options of Asset Tree - changing from "Custom" to "A-Z" or "Z-A" would also change order of script execution if it will be working same as pre-2.3, and sorting selection isn't saved in project (you can find it in %APPDATA%/GameMakerStudio2/<GMUSER>/Layouts/<PROJECT_NAME>), so it's not shared by developers, and that would cause even more random errors.

There's one safe way to run code before any room/instance is created, as they didn't removed it from docs, seems that gml_pragma("global", "FUNCTION_NAME()"); still works, so it should probably allow to set order of script execution on game start (remember that you can't access window/room/instances properties yet when using it). As long as it's defined in only one script, order should be known this way.
 
Top