GMS 2 GMS Game as "Headless"

Discussion in 'Tutorials' started by Bingdom, Dec 8, 2018.

  1. Bingdom

    Bingdom Googledom

    Joined:
    Jul 1, 2016
    Posts:
    1,655
    GM Version: GMS1.4 and Up
    Target Platform: Windows
    Download: N/A
    Links:
    https://www.yoyogames.com/blog/37/command-line-parameters-for-gamemaker-studio
    https://docs.microsoft.com/en-us/powershell/

    Summary
    We will begin first by creating .exe parameters. After that, we will start a GMS program as a "background process", and learn how to interpret parameters through GML. We then will monitor the console log through Windows PowerShell and demonstrate a powerful script.

    I have described this as "Headless" because I don't have a better name to describe it.

    This tutorial does not cover receiving instructions over a connection, or any server related material. This is more of an introduction on how you could make your application potentially headless.

    Tutorial
    Let's say you're making a game, and you've designed your game network's structural design to use a dedicated server.

    Now, you could write it in a different language, and have the benefits of multithreading. But let's say the network task must be completed in a month, and you don't have weeks to invest in a new language.

    You don't want to split your project into 2 parts, as managing 2 projects would be a monotonous task.

    You also don't want the host to deal with 2 applications. You'd want to give them the option to hide the window, right?

    Handling parameters
    Game maker has neat functions to deal with .exe parameters. They are parameter_count and parameter_string.
    To deal with such parameters, we will store them into an array. We will use a different version of the manual's example.
    Code:
    var p_num;
    p_num = parameter_count();
    for (var i = 0; i < p_num; i += 1) {
       p_string[i] = parameter_string(i);
    }
    Ok, we have the code, now how do we pass these "parameters".

    The answer is; it's easy. If you already know what to do, feel free to skip to Starting GM game as a background process.

    First, you'll need to export your game.
    Then, create a shortcut
    upload_2018-12-8_10-56-46.png

    Right click on that shortcut -> Go to properties.

    In the "Target" field, feel free to add all sorts of commands after the end of the directory.
    upload_2018-12-8_11-5-26.png

    Now if you draw your array, you should be able to see them.
    upload_2018-12-8_11-9-10.png

    These parameters function in any way you like. Try to make "noshaders" change the background colour, and make "gmc" change the font colour. If you do not know how, we will cover an approach with dealing with parameters in Making parameters functional.

    If you were making a multiplayer game, you can have ip address, port, hostname, host description, and other configuration data as parameters.

    Starting GMS applications as a background process
    This part is going to be short.

    All we need to do is have draw_enable_drawevent(false) in the create event. The GM window will not appear. So you'll need to kill it in task manager. Alternatively, you could set a timer to set the draw event to true, which will create the window.

    If we do this, the player would not be able to play your game (of course!). We would want this as a parameter like what we did before, right?

    Making parameters functional
    We want to give players an option to start the game with no window for their dedicated server, right? You can call your own parameter in any name you like, but in this case, we will name this parameter "-nowindow".

    We will grab the code that we used before, and use a switch statement to process the parameters.
    Code:
    var p_num;
    p_num = parameter_count();
    for (var i = 0; i < p_num; i += 1) {
       p_string[i] = parameter_string(i);
       switch(p_string[i]) {
          case "-nowindow":
             draw_enable_drawevent(false);
          break;
       }
    }
    Cool, we learnt how to pass in parameters and how to deal with them. But did you know that GMS has their own parameters? You can find a list of them here (applies to gms2 too).

    Tracking console output
    As mentioned earlier, GMS has their own parameters (which you can see here). If you've gone through the list, you may have noticed "-output".

    To quote what the website describes it as
    By using the function show_debug_message(), you will output text into this text file. Handy, isn't it?

    We will be using Windows Powershell to watch that file, but first, let's feed the shortcut an important parameter. We will not hide the window for now. Give it "-output log.txt". "log.txt" could be anything, but we will use this for this tutorial.

    log.txt should appear next to the .exe when you start the shortcut.
    upload_2018-12-8_11-46-8.png

    Now, each time we run the shortcut, GMS will keep stacking log data in the text file without removing it. We cannot delete the file in GMS, because GMS is already using it to output log data. This can be fixed if we create a PowerShell file (.ps1) that we'd use instead of a shortcut.

    Now, SHIFT + RIGHT CLICK into the whitespace, and click on "open PowerShell window here".
    [​IMG]

    Run the command "Get-Content log.txt -wait".
    I will not get into the details of Powershell commands. Please refer to their documentation.
    Now if you had show_debug_message calls, PowerShell will update live. Try to experiment with it.
    To stop PowerShell from logging, simply press Ctrl + C.

    You could have your PowerShell filter out specific commands.
    "Get-Content log.txt -wait | where { $_ -match "PLAYER_UPDATE>" }"
    Then in GMS, you'd use something like this
    Code:
    show_debug_message("PLAYER_UPDATE> " + string(newX) +" : " + string(newY))
    show_debug_message("WORLD_UPDATE> " + string(newWX) +" : " + string(newWY))
    It would filter out the commands by showing only the ones that contain "PLAYER_UPDATE>"

    To demonstrate the potential out of this, I have created a PowerShell script that;
    • Clears the log before starting the server
    • Reads a settings text file and adds it to the parameters of the server
    • Kills the server when shutdown-server or exit is called.
    • An easy "watch" function so non-programmers can start the logging process.
    • Monitors console log
    To stop PowerShell from logging, simply press Ctrl + C.
    Code:
    param($Work)
    
    #Restart PowerShell with -noexit, the same script, and 1
    if (!$Work) {
        powershell -noexit -file $MyInvocation.MyCommand.Path 1
        return
    }
    
    #Empty log data
    Clear-Content log.txt
    
    #Get server settings called "Server Settings.txt"
    $serverSettings = Get-Content "Server Settings.txt"
    
    #Start game as a dedicated server
    $dedicatedServer = Start-Process MyGame.exe "-nowindow -output log.txt $serverSettings" -PassThru
    
    #Kill server when exit or shutdown-server is called
    Register-EngineEvent PowerShell.Exiting -SupportEvent –Action {
        $dedicatedServer | Stop-Process
    }
    
    #Aleternative of exit. This makes no difference
    function shutdown-server {
        exit
    }
    
    #Shortcut of monitoring the console log
    function watch {
        Get-Content log.txt -wait
    }
    
    #Monitor console logs
    Get-Content log.txt -wait
    

    Thank you for reading. If you have any suggestions or problems, feel free to comment.
     
    Last edited: Dec 28, 2018
  2. icuurd12b42

    icuurd12b42 TMC Founder GMC Elder

    Joined:
    Apr 22, 2016
    Posts:
    1,828
  3. the_dude_abides

    the_dude_abides Member

    Joined:
    Jun 23, 2016
    Posts:
    411
    If I'm understanding the use for this correctly: it is allowing a program to be activated in the background, and use it when running some functions? Your example is for networking.

    One thing I have been curious about is whether two versions of gamemaker can be run on the same computer, and have them communicate information. I don't have the know how to figure if this tutorial could be used for that, so maybe you don't mind answering a noob question. Would some variation on the above make such a thing possible? or is that either the wrong application for it, or just not doable at all?
     
  4. Bingdom

    Bingdom Googledom

    Joined:
    Jul 1, 2016
    Posts:
    1,655
    There's no allowance for activation in the background. You can call draw_enable_drawevent(false) in the create event and it would still start windowless.
    In this tutorial, we're launching GM with parameters, and providing behaviours/ assigning attributes to those parameters. Once the app has started, we can no longer send instructions.

    It is possible to have another instance of GM to send instructions to your headless application (via networking). You could even send your log to it.

    Alternatively, you could write a CLI app (in C# for example) to communicate with your headless GM app.
     
  5. the_dude_abides

    the_dude_abides Member

    Joined:
    Jun 23, 2016
    Posts:
    411
    @Bingdom
    Thanks for the reply.

    As I said - I'm not the most technically minded person, or a talented programmer. Whenever I've run into performance issues there's the question of my capability versus the limits of Gamemaker Studio. One of the latter is whether it uses a single core of the CPU, or if it can use more than one.

    If it only uses one, and so is under utilizing the available power, then the idea of having two instances of the game running would be my noobs thought on how to get past that. One handles x amount of computing (a slave instance), while the other handles the rest as the master. The two communicate, and that data gets combined in the master.

    If such a thing were possible, and beneficial to performance, then I'd imagined some networking would be required between the two. So it's interesting to find out if this tutorial offers any path into that. Hopefully it's not a stupid thought, and I appreciate you taking the time to answer :) (and if it is silly, then fair enough...)
     
  6. FrostyCat

    FrostyCat Member

    Joined:
    Jun 26, 2016
    Posts:
    3,410
    Every version of GM thus far uses a single core. You can see this by running a project with a single infinite loop, where the most CPU it ever takes up is always 100 divided by the number of CPU cores on your system.

    It is 100% possible to do a MapReduce-like architecture through named pipes or even networking over localhost. The performance gains relative to a single process depends on the computation and the overheads of redistributing the work, but if you can get it to run in parallel it's usually worth it.
     
  7. the_dude_abides

    the_dude_abides Member

    Joined:
    Jun 23, 2016
    Posts:
    411
    @FrostyCat
    Thanks for the input Having gone through several variations of my AI, and struggling to get good performance, maybe it is time to look at other methods beyond optimization. Since there could well be a ceiling that limits it, that won't change no matter how good I get it. The idea that other available power of the CPU is not being utilized hopefully offers some leeway.

    This has been something at the back of my mind for a while, and whilst I may not have the understanding to do it (yet, at least) it is nice to know it can be done!
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice