From Steam to Floppy: Porting Modern TypeScript to Run on DOS

A.K.A. “The Update No One Asked For” – the exciting journey of getting the QuantumPulse 2A Command Line Interpreter to run on MS-DOS.

  1. Introduction
  2. Goals: System Requirements, DOS Jam, Single EXE
  3. First Attempts
  4. DOjS and jSH
  5. Optimization Break
  6. Modern TypeScript Pipeline Targeting DOS (jSH)
  7. Customized jSH and Win32 Port, Because, Why Not?
  8. Actually Building jSH
  9. jSH Launcher DOS Stub – One (Tiny) EXE to Rule Them All
  10. Sidebar: One Rabbit Hole Too Deep
  11. Conclusion

Introduction

I recently released QuantumPulse 2A, a “Zach-like” programming puzzle game, in which the player writes code for a fictional computer to solve challenges. The setting and theming is that of the earlier days of computing, building upon my own nostalgia for when I first started to learn to program.

As part of development, I already have a command-line interpreter (CLI) which can run a player’s program (and optionally check its correctness against the in-game puzzles), which is useful for things like validating leaderboard submissions. As part of my next update, I’d like to provide this CLI to users, so that the most engaged users can use it for things like testing their code directly from their favorite editor, or, as has been done in other similar games, writing an AI that modifies and tests solutions to find optimizations the humans have missed.

QuantumPulse is built entirely on web technology: my custom WebGL game framework GLOV.js, Node.js for tooling and back-end servers, and Electron for bundling those together with Chromium into a native app on Windows, Linux, and MacOS that I can release on Steam. It would be pretty easy to just release the CLI as a Node.js script, so that’s my fallback plan, but… could I do something more fun, more retro? What about releasing the CLI for MS-DOS? This could be fun if this works.

Goals: System Requirements, DOS Jam, Single EXE

I love low system requirements. If my games can run everywhere, that means they can bring joy to more people, and it prevents people from ever being surprised when it doesn’t run on their computer after they’ve already purchased it.

My native engine used in Splody (and Automato which is pretty actively used) runs on Windows XP, going so far as to even work on the native OpenGL software renderer included with Windows that gets used if you have no graphics drivers (which is actually useful if you ever want to run a bunch of copies in VMs for testing purposes, but only rarely useful for customers…). While working on Worlds FRVR, I’ve gone through some pretty extreme lengths to keep my WebGL framework working on 99.9% of our users’ devices, which, despite what “caniuse.com” will tell you, means, for mobile Chrome users, supporting back through Chrome v65, which is only slightly above the same capabilities as Internet Explorer – I actually test on IE regularly because that’s much easier to launch than trying to get Chrome 65 running on a modern computer running Windows 11 :D.

So, for QuantumPulse on Steam… this is total vanity, but, since discovering Steam allows you to type anything into the minimum requirements box, usually something like “Windows XP SP3 or newer”, I’d love to have QuantumPulse listed on Steam with a minimum system requirement of “MS-DOS 6.22” or something similarly nostalgic! How often do you see system specs like this on Steam, eh?

One of the other motivations for this is that the DOSember Game Jam caught my eye – a game jam with the goal of making playable content for DOS. So one of the goals here is to be able to share a QuantumPulse demo running on DOS with the DOSember jam community.

Another goal I have is to make the CLI a single executable which runs on both 16-bit DOS and modern Windows. The “Portable Executable” (PE) format used for modern Windows executables includes a rarely-used header segment where you can embed an arbitrary 16-bit DOS program called a “stub” (which DOS will just run, since the header is basically structured to look like that’s the only thing in the .EXE when interpreted by older DOS versions). Normally, this stub simply displays a message such as “This program cannot be run in DOS mode,” however since you can embed any small program in that stub, why not put something more interesting there, such as a fully functioning 16-bit version of program? So, that’s my goal: a single QP2ACLI.EXE which functions correctly when run in either MS-DOS or modern Windows, or anything in between, allowing people to “play” QuantumPulse in DOS.

Spoilers, jumping ahead a bit, here’s what it looks like in the end, solving a QuantumPulse puzzle entirely from within DOS.

First Attempts

The QuantumPulse CLI is not particularly complicated (about 3000 lines of TypeScript, if you exclude all of the puzzle test cases and such), so my initial thought is that I will just re-implement it in a language that compiles natively to both DOS and modern operating systems.

I first try a fork of GCC targeting DOS, thinking that maybe I could write a GCC-compliant program and just compile for both targets, but I run into various kinds of trouble there, and decide to first try something closer to what I know. What I do know is that in Visual Studio there’s a command line option (/STUB:FOO.EXE) to embed a DOS .EXE as the stub, so I want to get that working first as a proof concept.

Visual Studio, however, no longer lets you compile targeting DOS. I briefly consider installing Visual Studio 1.52 for Windows 3.11, which, presumably, would do so, but that seems likely to run into all sorts of trouble, so I decide instead to look at modern tooling that runs on Windows 11 and can build DOS executables. With the help of some very nice folks in the DOSember Jam Discord channel and a bunch of tooling around, I manage to get a simple program written in x86 assembly language to compile with NASM targeting 16-bit DOS, link it with appropriate options (/KNOWEAS) using MASM32, and then successfully link it as the DOS stub when compiling another program with modern Visual Studio. This works, but I really don’t want to have to be programming in assembly (I know, I know, the irony is palpable, considering that’s what QuantumPulse is about). After a bit more poking around, I set up Open Watcom V2.0 and manage to compile a test C program in a way that it works as the stub. The resulting .EXE runs on both DOS and Windows 11, so it works, but this is still a bit complicated, is there a simpler option?

Next, I briefly consider Free Pascal, not just for nostalgia reasons (I originally got started game programming in Turbo Pascal), but because it’s actively maintained for modern OSes and happens to still be able to target DOS from the same source code. This seems like a reasonably safe (and fun) solution.

> Or, I could do the Jimbly thing and write my own JavaScript interpreter for DOS…

Whether it’s C or Pascal though, I’d still be re-implementing a lot of the game in another language, which means additional maintenance headaches down the line, though that seems like a reasonable cost, until, while discussing this with a colleague, I jokingly say “Or, I could do the Jimbly thing and write my own JavaScript interpreter for DOS…”

DOjS and jSH

Since I’m already over my JavaScript-interpreters-per-year writing quota (having recently added a JavaScript-like scripting language to Worlds FRVR), I wisely don’t actually try to write my own JavaScript interpreter for DOS, however I do do a little digging and stumble upon a pair of projects DOjS and the simpler jSH, which is a “script interpreter for DOS based operating systems” supporting JavaScript (via a port of MuJS an ECMAScript/ECMA-262 interpreter). DOjS is a whole platform for making graphical apps (which I don’t need here), so I dive into jSH…

After some simple tests, I start hacking up my (Node.js-targeted) QuantumPulse CLI and manage to get something that functions under jSH. Quite a few things are different than node (such as how modules are required, how to access the filesystem), but it doesn’t take too much before my first successful run of a QuantumPulse program under DOS (and it’s even with all of the puzzle verification logic, which I was originally intending to not bother with). This is way simpler to set up and maintain than any of my other plans, so let’s do this!

Optimization Break

But, first, I think I need to do a little optimization. Running a simple QuantumPulse 2A program through jSH on DOSBox (simulating a 66MHz CPU, I think) takes about 20 seconds! A very quick investigation reveals this time is spent entirely loading my puzzles module, which generates all descriptions and test cases for all puzzles when it’s loaded. Totally wasteful to do this every time the program starts, I know, but, yep, after doing a quick check, I see it takes a total of 8ms on Chrome. Worrying about it before now would definitely have led to premature optimization, but now it’s time for that optimization… to mature… I guess. As well as the 20 seconds of time, it also allocates a worrying amount of memory (for DOS) – a couple MBs, a.k.a. a tiny fraction of a percent of the memory Chrome requires to simply display a purely blank page, so, again, totally irrelevant on a modern computer, but worth worrying about here.

I refactor my puzzle definitions to all be lazy-loaded and only generate what’s needed when it’s needed, this shaves off 8ms of startup time on Chrome (LOL), and now the QuantumPulse CLI on DOS loads, runs, and verifies a program in less than a second, success!

Modern TypeScript Pipeline Targeting DOS (jSH)

Now that I know how I want it to run, I want to abstract away the hacks I did so that my build pipeline can output something that’ll run on jSH with no manual tweaking required (so that whenever I do an update, the CLI in general and the DOS version specifically just keeps on working). Most of the trouble with jSH and my Node.js-focused code stems from a) how module loading works, and b) filesystem APIs that are provided in a slightly different way than Node.js. As it turns out, these 2 problems also pop up whenever you write code in Node.js and want it to run on a browser, which is something I’ve already got tooling around!

Just a little poking with Babel (instructing it to target an ancient version of Node.js) and Browserify and I’ve got my build system outputting a single .JS file with everything required bundled into it (and no reliance on either Node’s or jSH’s module systems). Browserify even has an easy way to override the “builtin” modules (like the filesystem access) so the code I write can keep calling the Node.js APIs and these (very small) overrides call the jSH APIs instead if appropriate. As an added benefit, since everything gets bundled into a single file, I can even move some of the jSH files into my build pipeline, so that the final distribution need only be the jSH EXE files and a single .JS file, removing the requirement on an additional JSBOOT.ZIP file that jSH otherwise uses to provide some APIs.

One last thing after getting the build pipeline working, it would be cool to allow this bundled JS file to also work on Node.js, as that’s widely supported on many operating systems (other than DOS) and has nice debugging features. Sure enough, just some simple tweaks in my jSH filesystem shim to just fall over to the Node.js API if it exists, and it works in either environment! The fs shim ends up looking like this, not too bad at all:

const IS_JSH = typeof JSH_VERSION !== 'undefined';

if (IS_JSH) {
  exports.readFileSync = function (filename) {
    let file = new File(filename, FILE.READ);
    let ret = [];
    let line;
    while ((line = file.ReadLine()) !== null) {
      ret.push(line);
    }
    file.Close();
    return ret.join('');
  };

  exports.existsSync = FileExists;

} else {
  // Node.js - do a native `require()` without Browserify
  // noticing and trying to intercept it.
  module.exports = eval('require')('fs');
}

I’ve provided a stand-alone example project at Jimbly/jsh-wrap-md5, which has a glov-build script which compiles a small TypeScript program (which pulls in a few NPM modules) through Babel and Browserify creating a bundle that runs directly on either Node.js or jSH. That’s right, it’s a modern TypeScript program running on DOS! As a caveat, Babel and Browserify aren’t what they used to be… I tried running a number of programs through this pipeline (specifically each of Babel and Browserfiy themselves :D), and the resulting JavaScript was not ECMA-262 compliant (nor would it even run on the ancient Node.js version I instructed them to target, that they used to support). Presumably some bugs with how it handles some language features have snuck in over the years, and you might have to use an older version of Babel to make this actually work (but, an older version of Babel may not support the newest JavaScript/TypeScript language features, somewhat defeating the point). It does work flawlessly for QuantumPulse, though I have a habit of avoid “new” language features that I know, even if they might technically work, will add a bunch of overhead to support old browsers.

Customized jSH and Win32 Port, Because, Why Not?

Now that I’ve got it working, I love jSH for this, but I have just a couple complaints: it prints out a message like “NO PACKET DRIVER FOUND” at startup if you do not have a TCP/IP driver installed under DOS (who does?!), it prints out “jSH OK” at the end of execution (cluttering the display of the useful information from the program), and the process’s exit status doesn’t actually reflect the exit status (e.g. if the program crashes or otherwise errors, it’s failing to signal to the OS that there’s an error, which inhibits using it in editor integrations or from within other scripts).

Luckily jSH is open source, so this seems like something I can fix. jSH is built using a fairly complex cross-build tool chain that involves using some version of GCC to compile DJGPP for Linux, and then using DJGPP to compile jSH for DOS. After I get it compiling locally (more details later on that), I start fixing these issues. The “NO PACKET DRIVER” message is coming from the TCP/IP library it links against, so I decide to just completely strip that out, which both fixes my complaint and results in cutting the JSH.EXE size in half (from about 1MB to 548KB)! The other issues are much simpler to fix. I’ve now got a JSH.EXE that works perfectly for QuantumPulse’s needs under DOS.

> I look longingly at that 0.5MB .EXE file

So… how about Windows? I could just bundle Node.js with it, but, let me check… the current version of Node.js when stripped of all tooling and dependencies is still about 100MB. I look longingly at that 0.5MB .EXE file and recall that DOjS (which shares a lot of code) claimed to have an experimental Win32 and Linux version available. I manage to get a build environment set up that can compile DOjS for Win32, and then after more time than I’d care to admit and a whole bunch of hacking and copying fixes around, I finally get jSH compiling for Win32. Final executable size on Windows: 376KB. Runs the QuantumPulse CLI flawlessly (and about 30% faster than Node.js, due to that 100MB overhead). Nice. I’ve put the modified code and binary releases at Jimbly/jSH.

Actually Building jSH

As alluded to earlier, building jSH isn’t exactly trivial. The build instructions require quite a few modules to be installed and quite a bit of setup, including building a particular version of DJGPP. I’ve seen similar things before and I know one of 2 things will be true: 1) these steps will stop working in the future due to some update somewhere in the supply chain, or 2) these steps already don’t work. As usual, it’s case #2.

I care passionately about reproducible builds. When I set up a project, especially one that involves some deep dive to get working at all, I want to be absolutely sure that when I come back to the project in months, or years, that I can make a change and trivially build for all targeted environments, ideally from anywhere, but especially from my home in Windows, without needing to manually install any dependencies nor remember anything about how I did it. In the past, this has led me to build Docker images for doing builds targeting the Steam Linux runtime (a particular set of system libraries guaranteed to be installed with the Steam Linux client) and so I can make my MacOS builds of Splody on Windows without ever touching a Mac.

> I rather dislike Docker containers to run apps, but I love Docker containers to reproducibly build apps

Docker is great for this. I rather dislike Docker containers to run apps, but I love Docker containers to reproducibly build apps, especially when cross-compiling. It lets me quickly iterate on which dependencies need to be installed for a build to work (without unknowingly pulling in something I’ve installed in the past for another project), but more importantly once I’ve got an image built, it’ll keep working on any computer, forever (assuming I push the image to Docker Hub or otherwise back them up).

With that in mind, I don’t even try manually building jSH (I know there’d be some conflict with other libraries I’ve got installed on my Linux box), but set straight to work on setting up a Docker image in which I can build jSH. It only takes a couple tweaks from the DJGPP and jSH build instructions – mostly pinning specific versions of things which, between now and when the instructions were written, have been updated in a way that is not backwards compatible, and adding a few packages that were required but not specifically called out (presumably because the original author had, unknowingly, already had them installed from some other work they were doing). After the image is built, it’s easy to run make within a Docker container while it access my (out-of-Docker) local source files with a command like docker run -i --rm -v /C/src/jsh:/project jimbly/jsh-build-dos make. Setting up the Win32 build image is a bit more work, but nothing major crops up.

If anyone wants to build DOjS or jSH via Docker, there’s a repo at Jimbly/jsh-build with all of the info, the source Dockerfiles if you want to re-build the Docker image, and example scripts for automating the Docker calls. The relevant Docker images are jimbly/jsh-build-dos and jimbly/jsh-build-win32 which in theory can be used to build any DJGPP project (though additional dependencies may be required).

jSH Launcher DOS Stub – One (Tiny) EXE to Rule Them All

Now I’ve got something working, but it involves running JSH.EXE QP2A.JS or JSH-W32.EXE QP2A.JS, which is slightly awkward, so I want to get back to my original goal of having a single executable that works on both (and doesn’t require the user manually invoking a JavaScript interpreter), so my goal is this: a single .C file that compiles to both 16-bit DOS and 32-bit Windows, and then links the former as the stub for the latter. This C file is just a simple program that massages the command line arguments and passes them on to launch the appropriate version of JSH.EXE for the platform it’s on. Removing some boilerplate and some logic to deal with the working directory, it’s basically just this:

int main(int argc, char *argv[]) {
  int i;
  const char *childargv[128];
#ifdef _WIN32
  childargv[0] = "CLI\\JSH-W32.EXE";
#else
  childargv[0] = "CLI\\JSH.EXE";
#endif
  childargv[1] = "CLI\\QP2A.JS";
  for (i = 1; i < argc; i++) {
    childargv[i + 1] = argv[i];
  }
  childargv[i + 1] = NULL;

  return spawnvp(P_WAIT, childargv[0], childargv);
}

I build the 16-bit version with Open Watcom (it’s 10KB), and then build the final Win32 version with Visual Studio. Huh, it’s pretty large, even with all optimizations, maybe I can use Open Watcom for the Windows build too? Yep, sure can. It’s not as slick as having a Visual Studio project where I just hit build and it builds everything, and I’ll forget the steps, so I make a build script I can use in the future any time I need to re-build this (which, probably, is never, but maybe I’ll do something similar for another project later…). A full example is here, but the build .BAT file is roughly as follows:

FOR %%a IN (%0\..) DO SET ROOT=%%~dpa
SET WATCOM=%ROOT%open-watcom-2_0-c-win-x64
SET PATH=%WATCOM%\BINNT;%PATH%
SET INCLUDE=%WATCOM%\H;%WATCOM%\H\NT

IF NOT EXIST build MD build

@echo Building for DOS...
wcc QP2ACLI.c -bt=dos -zq -w4 -os -ms -e25 -d0 -fo=build\QP2ACLI-DOS.obj

@echo Linking for DOS...
wlink op q name build\QP2ACLI-DOS.exe system dos file build\QP2ACLI-DOS.obj

@echo Building for Win32...
wcc386 QP2ACLI.c -w4 -e25 -zq -od -d0 -6r -bt=nt -fo=build\QP2ACLI-W32.obj -mf

@echo Linking everything...
wlink name build\QP2ACLI.EXE sys nt op maxe=10 op q op stub=build\QP2ACLI-DOS.exe file build\QP2ACLI-W32.obj

And there we go, I’ve got a nice small (42KB) wrapper which runs on either DOS or Windows and runs my (single-file) JavaScript app using an appropriate interpreter for the platform. All in all, with the wrapper, the .JS file, the two JSH interpreters, the entire thing weighs in at 1.05MB, that fits quite nicely on a floppy disk!

Sidebar: One Rabbit Hole Too Deep

This is great, I think, but I wonder, can I do better? This is where I recall seeing “Actually Portable Executables”, which is a version of a PE file which reportedly runs on Windows and Linux natively, built by a tool called “Cosmopolitan”. Since my program is not particularly complicated (just launching a child process), can I use the tricks they use to get this to run on Linux as well? The way they get their executable executing under both Windows and Linux is that they ensure the header of the Windows executable is also able to be parsed as a valid shell script under Linux. This requires a few tricks, but it seems the key is to have the first characters in the file look like MZ<any letters>='<arbitrary binary/header data>'; <actual shell script> so that it can ignore a block of binary data and then run some arbitrary commands. Unfortunately, the place in the EXE where it’s putting this all is exactly where the header of the 16-bit DOS stub lives (I suspect if you run an APE-format .EXE under DOS it’ll just die or hang).

Maybe I could make a DOS stub which happens to fit these requirements, but, it’ll be tricky, as basically every byte until I can squeeze in the =' has to be a byte that’s both valid for the DOS header and a valid shell identifier, and there’s a bunch of EXE header fields like “size of code” and “offset of relocation table” and such there, so it’d probably take a lot of trial and error and hacking… First step, though, is to try this out… I try making an arbitrary .EXE start with a valid script (but be totally invalid for DOS/Windows) and run it… and nothing happens. That’s odd. I try running the demo executables from Cosmopolitan… and nothing happens. A bit of poking and it seems these executables only work on very specific Linux shells (I could only get them to work in zsh, not sh or bash, which is what I’m usually in), otherwise it (correctly?) identifies it as something other than a shell script and doesn’t run it as one. Since my confidence of this even being possible was pretty low, and it wouldn’t actually just work for (presumably most) people, I decided, ya know what, the 2 people that ever try to run this on Linux can just type node CLI/QP2A.JS instead of ./QP2ACLI.EXE, it’s fine. I’ve still got a .JS file that runs under jSH on DOS and the latest Node.js on Linux, that’s cool.

Conclusion

So, where have I ended up as far as minimum system specs go? I’ve got this running in DOS using jSH, which is built with DJGPP which uses a 32-bit DOS extender, so that means it requires a 386SX CPU or better to run. As for what exact DOS version, I grab some DOS boot disks off of the Internet Archive and work my way backwards, proving it runs on MS-DOS 5.0, MS-DOS 4.01, and then MS-DOS 3.30. DJGPP says it’d work back to DOS 3.1, but I can’t find any easy way to test it, so I’ll just call it MS-DOS 3.30+. Maybe I should just advertise “MS-DOS 6.22” because that’s basically what everyone runs and all emulators are these days, and it’s got a heavy weight of nostalgia for me. Yeah, I think I’ll do that. But, we few, we happy few, we’ll know it actually runs on 3.30.

If you like a bit of this kind of low level stuff, but don’t actually want to be dealing with linkers and executable header formats, you may be the kind of person who’d enjoy playing QuantumPulse 2A, please check it out! The CLI is now included with both the demo and full game on Steam, and also available stand-alone on itch.

Also, if you’ve spent some time with QuantumPulse and want to leave a review, that would be really appreciated! Steam reviews are immensely valuable, as beyond certain thresholds Steam’s algorithms will show the game to more people, and they let players know what other players think of a game. And to me, beyond the business benefits, an honest review is great, it let’s me know what resonates with players and what doesn’t, and helps directs my future work.

Ludum Dare 42 Post-mortem: Escape from the Alliance

For those unfamiliar with it, Ludum Dare is a thrice-annual game creation competition in which you must create an entire game from scratch (including art, music, etc) in 48hrs. Participating is a lot of fun and really forces me to exercise my game designer muscles and dive into other parts of the game development process that I rarely spend time on. When I started working full-time on indie games at Dashing Strike, I vowed to participate in every Ludum Dare if possible, and this past one marks my 10th Ludum Dare in a row!

For those that haven’t played my entry yet, it’s a spaceship management game where you alternate between phases of fighting a wave of enemies and choosing which piece of equipment to remove from your ship, making you weaker but able to carry more refugees to safety, with a few little special events that influence your choices.

You can play the game here: dashingstrike.com/LudumDare/LD42

You can rate the game (if you competed in Ludum Dare), or see what people are saying about it here: ldjam.com/events/ludum-dare/42/escape-from-the-alliance

What Went Right

  • Scope – My game idea was fairly complicated, had very ambitious coding goals to finish it in time. I managed to implement most of what I planned, making a fairly complicated game (for a Ludum Dare entry), and after the tech work, I just barely ended with enough time to do sound, music, and add a little polish.

Continue reading “Ludum Dare 42 Post-mortem: Escape from the Alliance”

Indie Exhibiting at PAX East

When preparing for PAX East I saw this article from another indie dev, found it quite useful, and thought I’d share my experience, also as a first time exhibitor, complete with lot of interesting numbers.

My Booth

I exhibited Splody, my multiplayer action game that supports any number of players. I wanted to showcase this, so opted for a larger 20’x10′ booth and planned on having both an 8 player station and a 4 player station. I used two 55″ TVs, hooked up to tiny, cheap UltraSlim computers, with wireless controllers for all. One TV I put farther in the back, on a lower table the convention provided, so that I could get 4 sitting and 4 standing in front of it. The other TV I put on a stand, as high up as is comfortable to look at, closer to the aisle, so that people walking by had something to look at.

The ones with cat ears are my volunteers

Continue reading “Indie Exhibiting at PAX East”

Splody showing at GitHub / Ludum Dare GDC Party

Last night I attended the Ludum Dare / GitHub GDC party in San Francisco at the fantastic offices of GitHub.  I have no idea where their employees work (perhaps another floor?) but their gathering space was fantastic, and they even had a nice big TV with a dangling HDMI cable set up which I was able to snag for an hour or two of showing off my game, Splody.  I turned the TV over to Shnipers for the latter half of the night, as that was also a fantastic local multiplayer game, and had a chance to play a bunch of other indie games around the room as well.

The showing of Splody went quite well, often had 6 or more people playing at once, everyone seemed to be having fun, and quite a few were really excited about the game.  It was great to have so much positive feedback!  Everyone unanimously enjoyed my simultaneous multiplayer character customization/control test screen.

Simultaneous multiplayer character customization and control test screen

Now, I just need to channel as much attention as possible into getting Greenlit on Steam, so, if you have a Steam account, please go vote on my Steam Greenlight Campaign, every vote helps!

I did learn a few things that hadn’t came up with my previous demos – as this demo was to a bunch of random people at varying frequencies, and most of my previous demos have been to larger captive audiences.  I need a good way to show the game to just a single demoer – playing a 1v1 match against me, a tournament-winning Bomberman player, either doesn’t go well for them, or feels like I’m just committing suicide.  I think I’ll throw in an option to pad out a match to a fixed number with AIs, so if there’s just one person demoing, AIs can fill in so there is at least 4-6 players on screen for a better feeling of what a party game can be, though obviously playing against AIs isn’t as fun as stomping your friends.  The other thing was with one particular game mode, Mount Control, which currently has a bit of randomness in it which can lead to rather long matches, and I think I can do a little tuning so that the expected match time is a lot more constrained which would lead to much better conference-floor demo experiences.

Oh, and the other thing I learned, or, rather, already knew, but keep forgetting, is that I really shouldn’t play against a set of people and win 3 to 0 to 0 to 0 to 0 to 0… but some people playing the demo get really competitive and I have to give it my all to give them a fair fight, and the I forget to tone it down a notch for the next group.  Best solution is probably to continue talking about the game constantly, as me paying half attention is probably the right skill level for most people ;).

The horrible things people’s routers do to my packets!

Auto-updating software

So, over the years, I’ve released a few programs (all native C/C++) which have included automatic version checking, so they can let the user know when a new version is available. I’ve always done this by making a socket connection to my web server (previously Apache, now entirely Node.js) and asking for a file which just contains a version number. Pretty simple, right? Sure!

SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
connect(s, ...);
char cmd[] = "GET http://www.bigscreensmallgames.com/BestBombermanEver/version.txt HTTP/1.0\r\n\r\n";
send(s, cmd, sizeof(cmd), 0);
recv(s, ...);

And that’s about it.  Note:

  • This sends a single packet, and no router’s MTU is small enough that this packet would ever be fragmented, so it is, in theory, at least according to how TCP/IP is supposed to work, guaranteed to arrive as a single packet. Not that most web servers would care…
  • I don’t bother sending any headers, specifically the Host header. Why would I if this works?
  • There’s a bug in the code, it’s writing the NULL character into the packet after the final line feed.

Continue reading “The horrible things people’s routers do to my packets!”