One of the things I’ve had to deal with recently when using the Game Monkey scripting language, is how to ensure that scripts are executed in a certain order. This is important, as some scripts may rely on one or more objects that are created by other scripts. So these scripts must be executed first.
My scripts were just loaded in what ever order they were found while scanning a folder and its sub-folders. So there was no “nice” way I could enforce them to load in a given order, other than some stupid naming convention. I needed a solution to this problem.
How could I guarantee that certain scripts were executed before a certain point?
Solutions…
The first thing that sprang to mind, was how the c-processor manages this with #include directive to paste in other files containing type and identifier declarations. I needed something similar in Game Monkey, and I came up with two basic solutions to the problems.
- Grab an open-source c-preprocessor and add it to the the GM compiler so I could have the functionality of #include and all the other things that the c-preprocessor does.
- Add support to GM for something like #include as a keyword.
Both of these solutions had the same same draw back; I would have to make a lot of modifications to the GM parser to properly determine the file and line where an error occurs. It would be nice to be able to have conditional compilation in my scripts, so maybe the c-preprocessor support could be added later, but it was overkill for this problem.
It occurred to me that I was going about this the wrong way. I was thinking like I was trying to solve a C/C++ programming problem, and not a script problem. I started to think how I had exposed a native function to create an object in Muse.
For example, the script code below creates a material via the native function, “muCreateObject”.

Using a native function in script to create an object
Given that muCreateObject can be called from within a script function or outside of a function when the script is imported in a library to the VM, maybe I could do the same thing for “including” a script file.
After all, I just want to make sure that the script is executed before a certain point. A function to do this was exactly what I needed. So this is where we come to the implementing of the “import” function.
Implementing the import function
The import function is not all that special. The bulk of the work, which was not very much at all, was in my own code for managing the loading and execution of scripts. As an example of what import does, consider the following script code below;

Using the 'import' function
The table used in the call to muCreateObject references objects that were created in the NS_materials.gm, NS_skins.gm and NS_parts.gm script files. These script files were executed before the call to muCreateObject using the import function, which takes a path to a relative to the script file being currently executed for the script to “import”.
The import method performs the following steps
- The imported script path, is constructed relative to the path of the currently executing script
- Information about the script being imported is pushed onto a stack
- The imported script is loaded, and compiled
- Any errors in the imported script are output and the application exits.
- The imported script code is executed. Any calls to “import” in the script code cause the script manager to recurse back to step 1
- After the imported script has finished executing, the script information is popped from the stack and control is handed back to the Game Monkey VM.
All these steps were nothing more than an addition to the existing code that loads, compiles and executes script code on demand. A few additional checks were added that I hadn’t mentioned such as ensuring a script file is only executed once, and checking for something that might lead to an infinite loop due to a file trying to import itself.
Conclusion
In conclusion, the import function works very well.
It has the added benefit of being able to get rid of the file scanning code, in favour of loading a single main script file that imports other script files to be executed. This also means that there is now a known point where the engine enters the script code, making it easier in the future to add more flexible behavior via scripted functions.