GameMaker: Testing two game instances at once

If you are using GameMaker: Studio to create multi-player games (via not-so-recently added network_ functions or by utilizing existing DLLs) without separate projects for server and client, you might have stumbled upon one annoying limitation - you can't run two instances of game from IDE.

From a glance, this looks like a small issue, but it gets tedious really fast - to run a second instance, you have to either compile the game (takes time and monotonous file dialog actions), or find a compiled .win file in depth of temporary directories (or otherwise retrieve it's location via means of WinAPI), and pass it to the runner via command-line, like

...\AppData\Roaming\GameMaker-Studio\Runner.exe -game (path to *.win file)

But that's no fun, right?
At least I've found so.
So I took a bit of time and made a small GML snippet to lift this unfortunate limitation.

GM2022+ NOTE

This DLL is not x64-compatible and no longer works in the current GameMaker versions.

Please use MultiClient or execute_shell_simple.


The idea is simple.
Since GameMaker: Studio passes game file as a parameter to it's "runner" executable, game file location can be retrieved via parameter_* functions.
Then, there's the actual part with running a second game instance. Normally this would have been tricky, but I've made a DLL for that just recently, which adds a quite-so-convenient shell_execute function.
And, thinking of it, manually moving windows around also gets old fast, so may as well add that.
Combine the three, and this small nice snippet appears:

if (parameter_count() == 3) {
    shell_execute(parameter_string(0),
        parameter_string(1) + " " +
        parameter_string(2) + " " +
        parameter_string(3) + " -secondary")
    window_set_position(window_get_x() - window_get_width() div 2 - 8, window_get_y())
    // <primary instance>
    window_set_caption("P1")
}
if (parameter_count() == 4) {
    window_set_position(window_get_x() + window_get_width() div 2 + 8, window_get_y())
    // <secondary instance>
    window_set_caption("P2")
}

Where shell_execute is from earlier mentioned DLL file (for GM8x you can replace it with execute_shell), and -secondary, is, well, just a dummy parameter that we need to push parameter_count to a higher value. Don't remove it though! That would create a fork bomb. You certainly don't want to make one of those on accident.

And... that's it! Just in case any of this wasn't obvious, you can also download a sample project file with extension in it:

Download GMZ

Related posts:

17 thoughts on “GameMaker: Testing two game instances at once

  1. Here is a modified version that allow you to use steam and other stuff in the game and it will still create two instances of the game. You can also choose how many extra game instances it will start:

    /// Dual-start
    
    // Number Of Extra Players To Start
    var NumberOfChildren=1;
    
    // parameter_string(0)="C:\Users\Katarina\AppData\Roaming\GameMaker-Studio\Runner.exe"
    var RunnerPath=parameter_string(0);
    
    // Loop all other info until .win is found
    var OtherParameters="";
    var WinFile="";
    var ParameterAfterWinFile="";
    var HeadProgram=true;
    var State=0;
    for (var i=1; i<parameter_count(); i+=1)
    {
        switch (State)
        {
            case 0:
                // Search for .win
                if string_pos(".win",parameter_string(i))
                {
                    WinFile=parameter_string(i);
                    State=1;
                }    
                else
                {
                    // Not win just some info to add in queue
                    if OtherParameters=""
                    {
                        OtherParameters=parameter_string(i);
                    }
                    else
                    {
                        OtherParameters=OtherParameters + " " + parameter_string(i);
                    }
                }        
                break;
            case 1:
                ParameterAfterWinFile=parameter_string(i);
                HeadProgram=false;
                break;
        }
    }
    
    if HeadProgram
    {
        for (var i=0; i<NumberOfChildren; i+=1)
        {
            shell_execute(RunnerPath,OtherParameters + ' "' + WinFile + '" P' + string(i+2));
        }
        window_set_position(window_get_x() - window_get_width() div 2 - 8, window_get_y())
        window_set_caption("P1")    
    }
    else
    {
        window_set_position(window_get_x() + window_get_width() div 2 + 8, window_get_y())
        window_set_caption(ParameterAfterWinFile)    
    }
    • Just a heads up for anyone else reading, don’t deploy your game with the above code, it should only be for testing.

      The code searches for a .win file, and *when it finds it*, reads 1 more argument after it to check for the “secondary” flag (added by a previous iteration of this code to determine P1 or P2).

      The problem is that when the game is compiled, it doesn’t use the runner anymore, so there will never be a .win file, so “HeadProgram” can never be set to false, and so it creates a chain of newly opened programs thinking they’re the first iteration, and then trying to open more themselves, causing the computer to irrecoverably grind to a halt, to which the only solution is a hard power reset (fork bomb as mentioned in the article?).

      A compiled game only has 1 parameter, it’s the “special” one accessed with parameter_string(0).

      And it will be the path to your game’s exe:
      c:\\YourGame.exe
      or
      c:\Users\YourUsername\AppData\Local\Temp\IXP006.tmp\YourGame.exe
      if you used the self extracting standalone exe option when you compiled.

      This may be different if you use YYC I haven’t checked that.

  2. Works perfectly for me; thanks for your work on this.

    To anyone having trouble with it: I didn’t try the extension, but instead just added it to an existing project, so you might want to try that. Just import the extension (from the “extensions” directory in the example download), then copy+paste that code snippet from the article somewhere at the start of your game.

  3. Just downloaded the example file, but it doesn’t work for me :(
    I get only one window opening with the rotating crates.

    I am using Game Maker Studio (Pro edition), with Windows Vista. vcredist_x86 and vcredist_x64 are already installed.

  4. This post need a new reply I see :-)
    I got a message saying: "Unable to find game!!: c:\Users\Katarina\AppData\Local\\Jump"
    The correct path to the win file is:
    C:\Users\Katarina\AppData\Local\Temp\gm_ttt_22261\gm_ttt_16793\Jump Heroes.win

    Log file from gm:

    Asset Compile finished: 08:14:01
    -----------------------------------------------------------
    executing C:\Users\Katarina\AppData\Local\Temp\gm_ttt_22261\gm_ttt_16793\Jump Heroes.win
    -----------------------------------------------------------
    "C:\Users\Katarina\AppData\Roaming\GameMaker-Studio\Runner.exe"  -game "C:\Users\Katarina\AppData\Local\Temp\gm_ttt_22261\gm_ttt_16793\Jump Heroes.win"
    • Ahh. No space support: Now it works. Just changed:

              parameter_string(1) + " "
              parameter_string(2) + " "

      to:

              parameter_string(1) + " " + '"' +
              parameter_string(2) + " " + '"' +

      This add quotes in the path “Path to my fwin file with space in name”

  5. I keep getting “The program can’t start because MSVCP110.dll is missing from your computer. Try reinstalling the program to fix this problem.”

    It comes up 7 times, one for each method in the DLL.

    I’ve reinstalled vsredist.

    Will post here if I find a fix

  6. Nice trick, but it’s actually no problems having two instances of the same PROJECT open at once, as long as you don’t save them both at the same time. They’ll auto-update themselves and synchronize perfectly. That’s how I usually solve this problem.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.