<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://tsdo.in/feed.xml" rel="self" type="application/atom+xml" /><link href="https://tsdo.in/" rel="alternate" type="text/html" /><updated>2025-07-17T15:04:42+08:00</updated><id>https://tsdo.in/feed.xml</id><title type="html">What is TsFreddie doing?</title><subtitle>Professional Stuff Maker</subtitle><author><name>Freddie W</name></author><entry><title type="html">The Brutal Optimization of RPG Maker MV</title><link href="https://tsdo.in/blog/optimizing-rmmv/" rel="alternate" type="text/html" title="The Brutal Optimization of RPG Maker MV" /><published>2025-07-16T00:00:00+08:00</published><updated>2025-07-16T00:00:00+08:00</updated><id>https://tsdo.in/blog/optimizing-rmmv</id><content type="html" xml:base="https://tsdo.in/blog/optimizing-rmmv/"><![CDATA[<p>When a game you desperately want to play runs at 15fps and stutters constantly, you have two choices: give up, or dive deep into the engine’s guts with a profiler and some determination. This is how I managed to optimize a borderline unplayable game to a buttery smooth 144hz experience.</p>

<!--more-->

<blockquote>
  <p>NSFW Warning: Although this post does not describe any game content, the game mentioned contains mature, homosexual, and furry content.</p>
</blockquote>

<blockquote>
  <p>You can find the final optimization script <a href="https://github.com/TsFreddie/rmmv_optimization">here</a>.</p>
</blockquote>

<h2 id="its-not-rpg">It’s not RPG</h2>

<p>Despite the engine’s name, the game I am trying to optimize is far from being a traditional turn-based RPG game. Instead, it is a side-scrolling action game. Intuitively, this game is more heavy on scripts than a traditional RPG game.</p>

<p>If it wasn’t obvious, RPG Maker MV is just a JavaScript web game engine using PixiJS as the renderer and NW.js as the browser runtime. This, along with the fact that the engine code is not obfuscated, makes debugging it trivial in theory. However, reality hits you in the face almost immediately before you can even get started.</p>

<h2 id="unusable-devtool">Unusable DevTool</h2>

<p>The target game of my choice is “Polidog Patrol” which is the game I always wanted to play, but the framerate can drop as low as 15fps sometimes and the constant stuttering on my machine makes it unplayable.</p>

<p>Since NW.js is basically chromium, the chromium devtool has some incredible features for diagnosing JavaScript performance. RPG Maker MV actually blocks you from using the devtool by disabling the context menu and blocking F12 key events. However it is simple to comment out the event handling code:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// rpg_managers.js</span>
<span class="k">case</span> <span class="mi">123</span><span class="p">:</span> <span class="c1">//F12</span>
    <span class="k">if</span> <span class="p">(</span><span class="nx">Utils</span><span class="p">.</span><span class="nx">isNwjs</span><span class="p">())</span> <span class="p">{</span>
        <span class="nx">event</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">break</span><span class="p">;</span>
</code></pre></div></div>

<p>After that, I can simply open devtool by pressing F12… <strong><em>Oh no</em></strong>.</p>

<p>Upon opening the devtool, the game immediately drops to 5fps. The devtool itself is also almost unresponsive, clicking anything takes about 5 seconds to register. Despite the slowdown, it is still possible to navigate to the performance tab and record in the profiler. I just have to be patient. So I hit the record button, and let it record for 5 seconds. Recording that 5 seconds of gameplay took the devtool about 2 minutes to finish processing.</p>

<p>After the initial recording of the title scene, it is quite obvious which functions are the main culprit: <code class="language-plaintext highlighter-rouge">Game_Interpreter.command355</code> and <code class="language-plaintext highlighter-rouge">Game_Interpreter.command111</code>.</p>

<p><img src="/assets/imgs/2025-07-16-optimizing-rmmv/image_1.png" alt="Initial Profiler Result" /></p>

<p>Let’s take a look at what this <code class="language-plaintext highlighter-rouge">command355</code> is doing:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// rpg_objects.js</span>
<span class="nx">Game_Interpreter</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">command355</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">script</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">currentCommand</span><span class="p">().</span><span class="nx">parameters</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="dl">"</span><span class="se">\n</span><span class="dl">"</span><span class="p">;</span>
  <span class="k">while</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">nextEventCode</span><span class="p">()</span> <span class="o">===</span> <span class="mi">655</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">_index</span><span class="o">++</span><span class="p">;</span>
    <span class="nx">script</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">currentCommand</span><span class="p">().</span><span class="nx">parameters</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="dl">"</span><span class="se">\n</span><span class="dl">"</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="nb">eval</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>
  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>After a chuckle to myself, the <code class="language-plaintext highlighter-rouge">eval</code> call immediately jumped out. Let’s remember that the game does not actually run at the blazingly fast 5fps before we open the devtool. My hypothesis is that the <code class="language-plaintext highlighter-rouge">eval</code> call is somehow blocking the devtool due to some kind of chromium wizardry, and the sheer amount of <code class="language-plaintext highlighter-rouge">eval</code> functions being called per frame is choking the devtool.</p>

<p>To confirm my hypothesis, I need to somehow “eliminate” all the eval calls.</p>

<h2 id="pre-compiling-the-scripts">“Pre-compiling” the Scripts</h2>

<p>After taking a closer look at <code class="language-plaintext highlighter-rouge">Game_Interpreter</code>, I found that <code class="language-plaintext highlighter-rouge">command355</code> is basically the custom script block in the game’s script. It might be funny to you that the game’s “interpreter” is just calling <code class="language-plaintext highlighter-rouge">eval</code> functions with provided JavaScript code. But the actual interpreter does more than just running JavaScript code - it handles its own branching and looping (foreshadowing), and due to how the game script is structured, every <code class="language-plaintext highlighter-rouge">command355</code> block only runs one line of code. Apparently the game’s heavy usage of <code class="language-plaintext highlighter-rouge">command355</code> is making it very slow.</p>

<p>The game’s script/code is loaded by the engine from a series of JSON files (JSON as a programming language?). The interpreter then goes through a list in the structure line by line, or more accurately, item by item. I can’t really eliminate the <code class="language-plaintext highlighter-rouge">eval</code> call since the strings in the JSON file do need to be executed. However, I can wrap the code as a function and <code class="language-plaintext highlighter-rouge">eval</code> the function once on load, then call the function in place of every <code class="language-plaintext highlighter-rouge">eval</code> while the game runs.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Instead of running this every call</span>
<span class="nb">eval</span><span class="p">(</span><span class="nx">script</span><span class="p">);</span>

<span class="c1">// I can run this once when loading the JSON file</span>
<span class="kd">const</span> <span class="nx">func</span> <span class="o">=</span> <span class="nb">eval</span><span class="p">(</span><span class="s2">`(__)=&gt;{\n</span><span class="p">${</span><span class="nx">script</span><span class="p">}</span><span class="s2">\n}`</span><span class="p">);</span>

<span class="c1">// Then run this instead in place of original eval</span>
<span class="nx">func</span><span class="p">();</span>
</code></pre></div></div>

<p>I quickly whipped out a modification that intercepts the various loading methods and runs my custom “pre-compile” routine and stores all the functions in the interpreter instance.</p>

<p>This solved the eval problem by running all the required <code class="language-plaintext highlighter-rouge">eval</code> calls during load time. However, profiling revealed another performance bottleneck in the interpreter’s control flow.</p>

<h2 id="jumping">Jumping</h2>

<p>The engine’s <code class="language-plaintext highlighter-rouge">Game_Interpreter</code> also does branching and looping, which requires the interpreter to move to another part of the script list to continue execution. Here is how the interpreter handles the <code class="language-plaintext highlighter-rouge">else</code> statement:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// rpg_objects.js</span>
<span class="nx">Game_Interpreter</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">skipBranch</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
  <span class="k">while</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">_list</span><span class="p">[</span><span class="k">this</span><span class="p">.</span><span class="nx">_index</span> <span class="o">+</span> <span class="mi">1</span><span class="p">].</span><span class="nx">indent</span> <span class="o">&gt;</span> <span class="k">this</span><span class="p">.</span><span class="nx">_indent</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">_index</span><span class="o">++</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">};</span>

<span class="c1">// ...</span>

<span class="nx">Game_Interpreter</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">command411</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">_branch</span><span class="p">[</span><span class="k">this</span><span class="p">.</span><span class="nx">_indent</span><span class="p">]</span> <span class="o">!==</span> <span class="kc">false</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">skipBranch</span><span class="p">();</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>All <code class="language-plaintext highlighter-rouge">skipBranch</code> does is iterate through the list until it finds a command with a different indent level. Needless to say, this is also quite slow. However, it is possible to precompute the jump index for every index in the list. When <code class="language-plaintext highlighter-rouge">skipBranch</code> is needed, I can just set <code class="language-plaintext highlighter-rouge">this._index</code> to the precomputed value. Additionally, <code class="language-plaintext highlighter-rouge">command113</code> (Break Loop) does a different kind of jumping. And <code class="language-plaintext highlighter-rouge">command108</code> (Comment) is just comment blocks that the interpreter needs to skip through. I precomputed all the jump indices upon loading the JSON file and modified all the relevant commands to use the precomputed value.</p>

<p>After optimizing both the “script” calls and “jumping” commands, I returned to the trusty profiler to see whether improvements had been made. After opening devtool, it is obvious that the devtool is now very responsive. Here’s the new recording:</p>

<p><img src="/assets/imgs/2025-07-16-optimizing-rmmv/image_2.png" alt="Second Profiler Result" /></p>

<p><strong>Is that a 35x improvement I see?!</strong> Now the game runs at full speed. <strong><em>But wait</em></strong>, full speed it sure is! The game is running so fast that the gameplay is running at 2x speed now. After a bit of digging, I found that the game uses a <code class="language-plaintext highlighter-rouge">FpsSyncOption</code> plugin. By looking at the code and the way it is set up, it forces the game to update at every <code class="language-plaintext highlighter-rouge">requestAnimationFrame</code>. Since RPG Maker MV is designed to only run at 60fps, the engine logic is also framerate dependent. Due to my 144hz monitor, the game updates 144 times per second instead of 60. Turning off the <code class="language-plaintext highlighter-rouge">FpsSyncOption</code> plugin fixes the issue and the game runs beautifully at 60fps.</p>

<h2 id="fakeframes">FAKEFRAMES™</h2>

<p>The game running at its intended speed and framerate - what more could I want? Well, if I did have a 60hz monitor, or even a 120hz monitor, I probably would be very happy to be able to play the game at buttery smooth 60fps. However, since I have a 144hz monitor, rendering at 60fps actually introduces terrible frame pacing. Since the game is a side scroller, the jittery motion of the camera is very distracting.</p>

<p>The game I am trying to optimize is particularly interesting as an RPG Maker game - it doesn’t actually use much of the engine’s features. There are no “characters”, “battles” or any of the RPG elements. Essentially the game bypasses most of the engine’s gameplay features. Instead, the game opts to use lots of custom scripts and only “pictures” as its sprite system and “tilemap” as its map.</p>

<p>Now, since I want to render the game at high refresh rate, and the only thing I need to worry about is “picture” objects, I thought I can just intercept the picture rendering system and interpolate every picture’s position between current and last game ticks. Sure enough, it is a fine idea. I quickly implemented a picture interpolation system, and confirmed that it does work <em>almost</em> flawlessly. There are some quirks:</p>

<ul>
  <li>Some sprites teleport, yet interpolation would still try to smooth out the large movement gap. I added a distance check for this - if a picture moves too far across the screen, it resets the interpolation state and lets it teleport.</li>
  <li>Infinite scrolling sprites are done by teleporting back to the beginning, this introduces one frame of jitter when it teleports, making it not so seamless. I identified all the scrolling sprites and marked them as scrolling. Then every time they teleport, I also teleport the last frame’s position back using last frame’s delta to make it more seamless.</li>
</ul>

<p>This does introduce a tiny bit of input latency, but I’ve played through the game and it is not really noticeable. Most people are concerned about input latency when it comes to any type of interpolation. By interpolating from previous game update to current game update, you can say there is 1 frame of input latency. In reality, it is harder to define, since realistically, after the game processes the input, it changes from seeing the result of the frame to seeing the beginning of movement of that frame - you surely would notice your input being accepted even halfway through interpolation, so some might even say it’s only 0.5 frame of latency. In any case it still feels very responsive.</p>

<h2 id="moving-the-goalposts">Moving the Goalposts</h2>

<p>Now the game renders at high refresh rate with the power of FAKEFRAMES™. A new problem becomes immediately noticeable. The game can feel stuttery even when the framerate seems high enough. Well, since you can now see render updates at 144hz, our game logic’s CPU budget plummets from 16ms down to just under 7ms. Even if the game only runs the update 60 times per frame, reaching the budget limit of 7ms still delays the next interpolated frame, which introduces stutters.</p>

<p>In actual video game engines, if your game runs at 60 ticks per second with interpolation of some kind, you can get away with updating the game logic while rendering out the interpolated frames. Obviously, in a browser environment with single-threaded JavaScript, this is not possible. So we need to actually optimize the game as if it is targeting 144hz to squash the frame time to be consistently under 7ms.</p>

<p>With that goal in mind, I played the game normally, observed the behavior, and profiled the stuttering parts to identify further optimization opportunities. Here are the main bottlenecks I discovered and how I addressed each one:</p>

<h3 id="excessive-dom-elements">Excessive DOM Elements</h3>

<p>After each battle, there is a result overlay of the battle. I noticed sometimes when the overlay is shown, the game slows down quite significantly, but it doesn’t happen every time. There is a text sprite plugin <code class="language-plaintext highlighter-rouge">DTextPicture</code> - when the overlay is shown, the game creates multiple RPG Maker’s <code class="language-plaintext highlighter-rouge">Bitmap</code> instances each frame. Each frame contains an <code class="language-plaintext highlighter-rouge">HTMLCanvasElement</code>. I’m not entirely sure whether creating an excessive amount of canvas instances would slow down the browser, but after modifying the plugin to pool the <code class="language-plaintext highlighter-rouge">Bitmap</code> instances and reuse them as much as possible, the slowdown is gone.</p>

<h3 id="minimap-rendering-performance">Minimap Rendering Performance</h3>

<p>When the minimap is open, frame rate drops whenever the player moves. Profiling shows <code class="language-plaintext highlighter-rouge">Sprite_Minimap.update</code> takes up to 4ms. This is a custom sprite in the plugin <code class="language-plaintext highlighter-rouge">KMS_Minimap</code>. The plugin retrieves information about the tilemap and draws the minimap pixel by pixel by calling <code class="language-plaintext highlighter-rouge">Bitmap.fillRect</code> which essentially calls canvas context’s <code class="language-plaintext highlighter-rouge">fillRect</code>. Calling <code class="language-plaintext highlighter-rouge">fillRect</code> for every pixel seems to be slow. So I modified the plugin to have two different <code class="language-plaintext highlighter-rouge">Bitmap</code> instances - one for the current frame, and one for the previous frame. Whenever the player moves, I swap the Bitmap instances and clear the current one, calculate the overlapped area of the minimap, and blit the previous frame’s bitmap onto the current one. Then update the rest of the minimap as usual. I also added dirty flags to each tile of the tilemap in case the overlapping area also needs to be updated somehow. This way we only need to update the changed area of the minimap, instead of the entire thing every time it updates.</p>

<h3 id="decryption-bottleneck">Decryption Bottleneck</h3>

<p>Whenever the game loads an image or audio file, the engine also needs to decrypt them. For audio files specifically, whenever audio plays, the game actually loads the audio from scratch again. Chromium is pretty good at caching the file access, but after the file loads, the engine decrypts the audio file synchronously. This can be very expensive whenever there is more than one audio playing at the same time. I modified the game to use a decryption worker to decrypt the audio file on a separate thread. This way the decryption is done asynchronously although the worker still only does one decryption at a time. But the decryption routine no longer blocks the main thread.</p>

<h3 id="sprite-tinting-cache">Sprite Tinting Cache</h3>

<p>RPG Maker MV can tint a sprite by creating a canvas and running various filters then reading back the canvas data to use as image data. This only happens once when the sprite is tinted. However, in the late game, there are flicker effects for game character sprites done by updating the tint of an image each frame. When multiple flickering characters are on screen, multiple tinting routines run every frame. I modified the tinting routine to cache the tinted image data after it is tinted by their tint parameters. This way, the tinting routine only needs to run once for each sprite, and can be retrieved back from the cache whenever the same sprite with the same tint color is used.</p>

<h3 id="optimizing-picture-management">Optimizing Picture Management</h3>

<p>Probably for ease of managing sprites by assigning them large IDs with actual meanings (which is common in game development), the game requested the engine to provide a picture bank of 10,000 pictures. Each frame, the game iterates through all 10,000 picture IDs to update them. Obviously the game doesn’t actually render 5 digits worth of sprites. It usually only has about 100 pictures shown at any time. So I modified the game picture system to put active pictures into a separate container, then only update the active pictures. I also updated the FAKEFRAMES™ to only iterate through active pictures too.</p>

<h3 id="z-index-sorting-optimization">Z-Index Sorting Optimization</h3>

<p>The game uses a <code class="language-plaintext highlighter-rouge">PictureZIndex</code> plugin to assign pictures with a z-index value. Without this plugin, the game renders from picture 1 to picture 10,000 in order, therefore putting pictures with higher IDs on top. The game uses the plugin to dynamically adjust the z-index of pictures. However, the plugin sorts the picture container every time a picture’s z-index is changed. In some cases, the z-index is set multiple times per frame, and, remember, the game is sorting 10,000 pictures every time. Given the simplicity of the plugin, I nuked the plugin and rewrote it entirely by assigning the z-index and managing a dirty flag to make sure the pictures are sorted correctly right before the engine renders them. Making sure the game sorts at most once per frame.</p>

<h2 id="conclusion">Conclusion</h2>

<p>I’ve completed the game and the game is also optimized to the best of my ability. Using RPG Maker MV to make a non-RPG is no small feat. The game engine and its plugins are perfectly suited for turn-based RPGs where logic and graphical changes usually happen only every so often. But they ultimately fall short when it comes to making anything else that requires a more intensive game loop.</p>

<p>These optimizations are very game-specific, and I cannot promise they will work for other games. I have sectioned the optimization script with headers to explain their purpose. If you also use RPG Maker MV and want to optimize your game, hopefully this write-up can give you some ideas.</p>

<p>Ironically, going back and forth between playing and optimizing is not really a good way to play video games. I hope this optimization work will benefit other players more than myself. But I also hope someday I can completely forget about the game so I might be able to enjoy the buttery smooth game in 144hz like a normal person.</p>

<p>Here’s the final profiler record after everything:</p>

<p><img src="/assets/imgs/2025-07-16-optimizing-rmmv/image_3.png" alt="Final Result" /></p>]]></content><author><name>Freddie W</name></author><category term="Blog" /><category term="RPG Maker" /><category term="Profiling" /><category term="Debugging" /><category term="JavaScript" /><category term="Optimization" /><summary type="html"><![CDATA[When a game you desperately want to play runs at 15fps and stutters constantly, you have two choices: give up, or dive deep into the engine’s guts with a profiler and some determination. This is how I managed to optimize a borderline unplayable game to a buttery smooth 144hz experience.]]></summary></entry><entry><title type="html">How to Test or Debug Steam Networking</title><link href="https://tsdo.in/blog/test-steam-networking/" rel="alternate" type="text/html" title="How to Test or Debug Steam Networking" /><published>2024-09-28T00:00:00+08:00</published><updated>2024-09-28T00:00:00+08:00</updated><id>https://tsdo.in/blog/test-steam-networking</id><content type="html" xml:base="https://tsdo.in/blog/test-steam-networking/"><![CDATA[<p>I have worked at several companies who develop multiplayer video game projects. Anyone who’s been through the process of developing multiplayer games probably shares the pain of juggling multiple running games at the same time. Just to find out the game still breaks when three or more players are connected during testing.</p>

<p>Regardless of the difficulty of testing multiplayer games. The initial development process still involves launching multiple instances just to see if they connect. During all my past experiences, this stage is usually done locally on a single workstation. Having one socket connect to another local socket involves very little effort: hardcoding “localhost” as the address and click the magical “host” and “connect” test buttons (which you would’ve coded yourself of course).</p>

<p>However, integrating with target platforms like Steam make things a little bit more complicated.</p>

<!--more-->

<blockquote>
  <p>TL;DR:</p>

  <ol>
    <li>Launch Steam with <code class="language-plaintext highlighter-rouge">-master_ipc_name_override ipc_name -userchooser</code> to launch a new Steam instance with a different IPC name and sign in with another Steam account.</li>
    <li>Launch your game with <code class="language-plaintext highlighter-rouge">steam_master_ipc_name_override</code> environment variable set to the name you used (e.g. <code class="language-plaintext highlighter-rouge">ipc_name</code>) before initializing Steamworks SDK.</li>
    <li>Do this for every new instance with different IPC name.</li>
  </ol>
</blockquote>

<h2 id="steam-is-not-actually-single-instanced">Steam is (not actually) single instanced</h2>

<p>By default, you can only open one Steam on your computer. You can open multiple instances of your game and initialize Steamworks SDK on all of them just fine. But once you started trying to send a message to the other instance through Steam Networking, you’ll realize Steamworks SDK uses Steam ID as the identifier of the connection source and destination (Example: <a href="https://partner.steamgames.com/doc/api/ISteamNetworkingMessages#SendMessageToUser">SendMessageToUser</a>). You might realize the two instances share the same Steam ID as they are both logged in with the same account.</p>

<p>Now, if we could launch two Steam with different accounts, this wouldn’t be a problem anymore. Let’s figure out how to do exactly that.</p>

<p>Launching a second Steam is actually easier than you thought. Steam communicates with it’s SDK via a IPC mechanism, each IPC is named with a unique string. If you override the IPC name, Steam will launch a new instance for that name. We can do that by passing the following command line arguments while opening Steam:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">-master_ipc_name_override</span> testing <span class="nt">-userchooser</span>
</code></pre></div></div>

<p>You can replace <code class="language-plaintext highlighter-rouge">testing</code> with any name you want. The <code class="language-plaintext highlighter-rouge">-userchooser</code> argument is to make sure Steam opens the user chooser dialog instead of automatically logging in with your main account <em>again</em>.</p>

<h2 id="make-your-game-recognize-the-second-steam">Make your game recognize the second Steam</h2>

<p>If you open two game instances from your game engine or project directory, you’ll notice that they are still both logged in with your main account. Now you have three choices:</p>

<ol>
  <li>
    <p>Upload your game to a Steam Depot and download it to the second Steam. Open the game via Steam as usual.</p>
  </li>
  <li>
    <p>Add your game as a non-Steam game to the second Steam. Then you can launch it that way.</p>
  </li>
  <li>
    <p>My favorite choice: set a <code class="language-plaintext highlighter-rouge">steam_master_ipc_name_override</code> environment variable before initializing Steamworks SDK. You can do this before launching your game or during your game’s initialization, as long as it is set before you call <a href="https://partner.steamgames.com/doc/api/steam_api#SteamAPI_Init"><code class="language-plaintext highlighter-rouge">SteamAPI_Init</code></a>. This way you can launch your game directly without opening it through Steam.</p>
  </li>
</ol>

<p>You might have guessed it already: all three methods above are actually the same. Steam just set the environment variable for you if you launch it through the store’s interface.</p>

<h2 id="why-is-this-not-documented-anywhere">Why is this not documented anywhere?</h2>

<p>Believe me, I already tried to do exactly this before. However, searching “testing steam networking” usually leads you to believe you need multiple machines to test your game.</p>

<p>I only found this method recently after I randomly decided to search “opening multiple steam” instead. There are quite a few guides on how to do that with the perspective of players who are trying to login their game with multiple accounts. After a enviroment variable dump in the second Steam, the solution finally revealed itself to me. Retroactively searching <code class="language-plaintext highlighter-rouge">master_ipc_name_override</code> and <code class="language-plaintext highlighter-rouge">steam_master_ipc_name_override</code> in the Steamworks official documentation also give you zero results.</p>

<p>Anyway, I actually can’t believe this took me three years to figure out. I’ve been testing our games on multiple machines as informed, or even worse - by calling my friends to help then disappoint them when the new update simply doesn’t work. I hope this post can save some friendship in the future like it might have saved mine.</p>]]></content><author><name>Freddie W</name></author><category term="Blog" /><category term="Steam" /><category term="Networking" /><category term="Publishing" /><category term="Debugging" /><summary type="html"><![CDATA[I have worked at several companies who develop multiplayer video game projects. Anyone who’s been through the process of developing multiplayer games probably shares the pain of juggling multiple running games at the same time. Just to find out the game still breaks when three or more players are connected during testing. Regardless of the difficulty of testing multiplayer games. The initial development process still involves launching multiple instances just to see if they connect. During all my past experiences, this stage is usually done locally on a single workstation. Having one socket connect to another local socket involves very little effort: hardcoding “localhost” as the address and click the magical “host” and “connect” test buttons (which you would’ve coded yourself of course). However, integrating with target platforms like Steam make things a little bit more complicated.]]></summary></entry></feed>