{"article":{"slug":"a-custom-virtual-machine-for-the-stars-4x-game","title":"A custom virtual machine for the Stars! 4X game","subtitle":null,"summary":"Chris Wellons builds a custom virtual machine to host AI players for the classic Stars! 4X game, covering bytecode design, performance, and interfacing with the original binary.","content_type":"blog_post","language":"en","canonical_url":"https://nullprogram.com/blog/2026/09/17/","author":{"name":"Chris Wellons","url":"https://nullprogram.com/","person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"null program","url":"https://nullprogram.com/","listing_slug":null,"listing":null},"topics":[{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"Systems Programming","slug":"systems-programming","url":"https://listedarticles.com/topics/systems-programming"},{"name":"Gaming","slug":"gaming","url":"https://listedarticles.com/topics/gaming"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":1116,"reading_minutes":5,"published_at":"2026-09-20T15:09:11.623Z","added_at":"2026-09-20T15:09:11.623Z","updated_at":"2026-09-20T15:09:11.623Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/a-custom-virtual-machine-for-the-stars-4x-game","markdown_url":"https://listedarticles.com/articles/a-custom-virtual-machine-for-the-stars-4x-game.md","example":false,"citation":"Chris Wellons, null program. \"A custom virtual machine for the Stars! 4X game.\" 20 Sept 2026. https://nullprogram.com/blog/2026/09/17/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://nullprogram.com/blog/2026/09/17/"},"body_markdown":"nullprogram.com/blog/2026/09/17/\n  \n\n  Stars! is a 1995 4X game (explore, expand, exploit, exterminate)\nfor 16-bit Windows 3.1 that I first played ~28 years ago. While Windows is\nfamously backwards compatible, it’s notoriously difficult to play Stars!\ntoday. Windows x64 cannot run 16-bit applications, and playing requires\neither retro hardware or emulation (otvdm, DOSBox), sometimes\npaired with Wine. My new, exciting solution, **Stars!VM**, or\n*Stars! Virtual Machine*, embeds a custom 80286 emulator and a Win16\nto Win32 bridge. As native Win32, the game looks and feels exactly as it\ndid originally, except sporting a modern file chooser and 4k scaling. It’s\nindistinguishable from a genuine 32-bit or 64-bit port of the game,\nespecially with the original 16-bit game embedded inside the VM\nexecutable.\n\nThe signed releases on GitHub embed a compressed copy of the original\n16-bit game, so that single EXE is ready to play out-of-the-box with no\nfurther setup or downloads. I’m distributing 32-bit builds (but requires\nSSE2) because there’s no advantage to 64-bit here, and these builds work\n(almost) everywhere *except* 16-bit Windows. 32-bit Windows could run the\noriginal 16-bit game, but the VM-encapsulated version is better behaved.\nIt doesn’t dump a `Stars.ini` under `C:\\WINDOWS`, it interacts properly\nwith the task bar, and copy protection is neutralized via the OS bridge.\n\nIf you ever been curious about Stars!, now’s the time to try it. The game\nhas a thorough, built-in tutorial, but also check out the wiki, the\nofficial strategy guide, and AutoHost (play-by-email service).\nThe game predates the modern search engine concept, otherwise they might\nhave chosen a better name. I suggest using “stars 4x” in your searches.\n\nIf you want to build from source and hack on the VM yourself, the best\ntool for the job is w64devkit, of course, because it comes with\neverything you’ll need. Plus the game itself: `stars.exe`\nfrom `stars27jrc3.zip`.\n\n### Implementation details\n\nThe emulator itself requires x86 or x86-64 because it does not implement\nx87 (80-bit floating point) in software, but instead runs these operation\ndirectly on the host’s x87 hardware. This is simple, fast, and precise.\nThe project validates the emulation as a whole with a differential fuzzer\nagainst the host. The fuzzer randomly generates a 16-bit instruction,\nemulates it, then runs it with JIT on the host and compares the\nresults.\n\nHandles on Windows are pointer-sized, and so the Win16-to-Win32 bridge\nmaps 16-bit handles to host handles. It marshals between different struct\nlayouts when translating these calls, services the DOS interrupts the game\nrequires, an copies data in and out of guest memory. It’s rather like\nrunning a Wasm instance, which of course makes sense in retrospect.\n\nThe Win32 bridge is also monitorable and manipulatable using the Model\nContext Protocol (MCP). AI agents can “see” the UI “DOM” as it’s built,\nand can drive it by injecting synthetic events into the event pump, all\nwithout going through the usual desktop control. The MCP can also read and\nwrite guest memory. Opus 5 played a complete game through MCP — which is\nquite fun to watch — requesting my assistance at just two points when it\ngot stuck in the UI. A foundation for a new Stars!Bench?\n\nTargeting old 16-bit computers, the authors couldn’t afford to build a\nsloppy, wasteful UI, and so by modern standards the game UI is remarkably\nfast and responsive. They don’t make ‘em like they used to. Computing the\nnext turn, or “turn generation,” is the computational bottleneck, and so\nthat’s where I focused my optimization efforts. The emulator can trace\nexecuted instructions, so I gathered traces of turn generation, then had\nFable 5.1 identify and reverse engineer the hottest common routines (e.g.\nthe game’s L’Ecuyer MCG PRNG) and basic blocks. Each was re-written in C\nand mapped into the instruction decoder as new 80286 instructions. On load\nthe emulator identifies these routines and patches them with the new\ninstruction. This resulted in a nearly ~2x speedup of turn generation. By\nexploiting local conditions, emulating a particular known program, I get\nJIT performance without JIT complexity.\n\nThe original game doesn’t use buffered I/O, and instead issues many\nsmall reads and writes. Passing these small reads/writes straight to Win32\nmade I/O take ~5% turn generation time, probably worse today than it was\nback then. Plus it’s just rude. The emulator buffers the game’s I/O calls,\nfurther speeding up turn generation.\n\nThe game has some sound effects in the “battle VCR” and the final version\nof the game shipped with Microsoft’s `WaveMix.dll`. Rather than load and\nlink this DLL, the emulator implements the DLL’s interfaces natively, and\nthese routines are dynamically linked into the 16-bit process. You will\nnot need this DLL with the emulator, nor is it embedded in releases.\n\nThe game also has art assets embedded uncompressed in the original EXE,\nforming the bulk of its ~3MB. Stars!VM uses a custom LZ-based compression\nalgorithm tailored to compressing the original game. It’s compressed when\nembedded in releases. So the 32-bit version of the game is half the size\nof the original, at ~1.5MB.\n\nThe original game requires a serial code, serving as its copy protection.\nA code is 8 alpha-numeric characters that must pass two checks. Failing\nthe first is loud, but failing the second will sabotage your game with\npenalties. You’ll know because it will announce that your people suspect\nyou are a usurper. Most codes you’ll find online are such “usurper” codes.\nPlay-by-email (PBEM) saves embed a hardware signature derived from C and D\ndrive configuration. People playing on different machines using the same\nserial code recieve the usurper penalty.\n\nI bought a serial code back in the day, but it hasn’t been possible to\npurchase one a for at least decade now. So the emulator injects a fixed\nserial code on first run (disable with `--prompt-serial`), and you won’t\nneed to worry about it. The VM also produces a fixed hardware signature\n(same as any other emulator), so it looks like everyone running Stars!VM\nis sharing the a machine, meaning no penalty for key reuse. I cracked the\nserial code checks anyway, allowing me discover interesting ones. My\nfavorites: CLONEMUM, CROSSNUT, EGGSWAIN, GHOSTKIN, GONKSHOW, GRIPMIME,\nSEEKCAPS, SIFTBOLD, SIRBUOYS, SLIMFAZE, SLOTMOPS, SPAWNELK, SUNBLOND,\nWANTNEAR, and WRONGPOX. These look like some of my passwords.\n\n### Endless possibilities\n\nI’m quite pleased and excited with the results, especially for a weekend\nproject. It’s breathed life back into the game for me, not only having a\nbetter experience running it, but also that I can trivially bend the game\nto my will in the ways I dreamed about. A few hooks in the right places\nshould open the game to easy modding, but I’m more engineer than modder.","body_html":"<p>nullprogram.com/blog/2026/09/17/</p>\n<p>  Stars! is a 1995 4X game (explore, expand, exploit, exterminate)\nfor 16-bit Windows 3.1 that I first played ~28 years ago. While Windows is\nfamously backwards compatible, it’s notoriously difficult to play Stars!\ntoday. Windows x64 cannot run 16-bit applications, and playing requires\neither retro hardware or emulation (otvdm, DOSBox), sometimes\npaired with Wine. My new, exciting solution, <strong>Stars!VM</strong>, or\n<em>Stars! Virtual Machine</em>, embeds a custom 80286 emulator and a Win16\nto Win32 bridge. As native Win32, the game looks and feels exactly as it\ndid originally, except sporting a modern file chooser and 4k scaling. It’s\nindistinguishable from a genuine 32-bit or 64-bit port of the game,\nespecially with the original 16-bit game embedded inside the VM\nexecutable.</p>\n<p>The signed releases on GitHub embed a compressed copy of the original\n16-bit game, so that single EXE is ready to play out-of-the-box with no\nfurther setup or downloads. I’m distributing 32-bit builds (but requires\nSSE2) because there’s no advantage to 64-bit here, and these builds work\n(almost) everywhere <em>except</em> 16-bit Windows. 32-bit Windows could run the\noriginal 16-bit game, but the VM-encapsulated version is better behaved.\nIt doesn’t dump a <code>Stars.ini</code> under <code>C:\\WINDOWS</code>, it interacts properly\nwith the task bar, and copy protection is neutralized via the OS bridge.</p>\n<p>If you ever been curious about Stars!, now’s the time to try it. The game\nhas a thorough, built-in tutorial, but also check out the wiki, the\nofficial strategy guide, and AutoHost (play-by-email service).\nThe game predates the modern search engine concept, otherwise they might\nhave chosen a better name. I suggest using “stars 4x” in your searches.</p>\n<p>If you want to build from source and hack on the VM yourself, the best\ntool for the job is w64devkit, of course, because it comes with\neverything you’ll need. Plus the game itself: <code>stars.exe</code>\nfrom <code>stars27jrc3.zip</code>.</p>\n<h3 id=\"implementation-details\">Implementation details</h3>\n<p>The emulator itself requires x86 or x86-64 because it does not implement\nx87 (80-bit floating point) in software, but instead runs these operation\ndirectly on the host’s x87 hardware. This is simple, fast, and precise.\nThe project validates the emulation as a whole with a differential fuzzer\nagainst the host. The fuzzer randomly generates a 16-bit instruction,\nemulates it, then runs it with JIT on the host and compares the\nresults.</p>\n<p>Handles on Windows are pointer-sized, and so the Win16-to-Win32 bridge\nmaps 16-bit handles to host handles. It marshals between different struct\nlayouts when translating these calls, services the DOS interrupts the game\nrequires, an copies data in and out of guest memory. It’s rather like\nrunning a Wasm instance, which of course makes sense in retrospect.</p>\n<p>The Win32 bridge is also monitorable and manipulatable using the Model\nContext Protocol (MCP). AI agents can “see” the UI “DOM” as it’s built,\nand can drive it by injecting synthetic events into the event pump, all\nwithout going through the usual desktop control. The MCP can also read and\nwrite guest memory. Opus 5 played a complete game through MCP — which is\nquite fun to watch — requesting my assistance at just two points when it\ngot stuck in the UI. A foundation for a new Stars!Bench?</p>\n<p>Targeting old 16-bit computers, the authors couldn’t afford to build a\nsloppy, wasteful UI, and so by modern standards the game UI is remarkably\nfast and responsive. They don’t make ‘em like they used to. Computing the\nnext turn, or “turn generation,” is the computational bottleneck, and so\nthat’s where I focused my optimization efforts. The emulator can trace\nexecuted instructions, so I gathered traces of turn generation, then had\nFable 5.1 identify and reverse engineer the hottest common routines (e.g.\nthe game’s L’Ecuyer MCG PRNG) and basic blocks. Each was re-written in C\nand mapped into the instruction decoder as new 80286 instructions. On load\nthe emulator identifies these routines and patches them with the new\ninstruction. This resulted in a nearly ~2x speedup of turn generation. By\nexploiting local conditions, emulating a particular known program, I get\nJIT performance without JIT complexity.</p>\n<p>The original game doesn’t use buffered I/O, and instead issues many\nsmall reads and writes. Passing these small reads/writes straight to Win32\nmade I/O take ~5% turn generation time, probably worse today than it was\nback then. Plus it’s just rude. The emulator buffers the game’s I/O calls,\nfurther speeding up turn generation.</p>\n<p>The game has some sound effects in the “battle VCR” and the final version\nof the game shipped with Microsoft’s <code>WaveMix.dll</code>. Rather than load and\nlink this DLL, the emulator implements the DLL’s interfaces natively, and\nthese routines are dynamically linked into the 16-bit process. You will\nnot need this DLL with the emulator, nor is it embedded in releases.</p>\n<p>The game also has art assets embedded uncompressed in the original EXE,\nforming the bulk of its ~3MB. Stars!VM uses a custom LZ-based compression\nalgorithm tailored to compressing the original game. It’s compressed when\nembedded in releases. So the 32-bit version of the game is half the size\nof the original, at ~1.5MB.</p>\n<p>The original game requires a serial code, serving as its copy protection.\nA code is 8 alpha-numeric characters that must pass two checks. Failing\nthe first is loud, but failing the second will sabotage your game with\npenalties. You’ll know because it will announce that your people suspect\nyou are a usurper. Most codes you’ll find online are such “usurper” codes.\nPlay-by-email (PBEM) saves embed a hardware signature derived from C and D\ndrive configuration. People playing on different machines using the same\nserial code recieve the usurper penalty.</p>\n<p>I bought a serial code back in the day, but it hasn’t been possible to\npurchase one a for at least decade now. So the emulator injects a fixed\nserial code on first run (disable with <code>--prompt-serial</code>), and you won’t\nneed to worry about it. The VM also produces a fixed hardware signature\n(same as any other emulator), so it looks like everyone running Stars!VM\nis sharing the a machine, meaning no penalty for key reuse. I cracked the\nserial code checks anyway, allowing me discover interesting ones. My\nfavorites: CLONEMUM, CROSSNUT, EGGSWAIN, GHOSTKIN, GONKSHOW, GRIPMIME,\nSEEKCAPS, SIFTBOLD, SIRBUOYS, SLIMFAZE, SLOTMOPS, SPAWNELK, SUNBLOND,\nWANTNEAR, and WRONGPOX. These look like some of my passwords.</p>\n<h3 id=\"endless-possibilities\">Endless possibilities</h3>\n<p>I’m quite pleased and excited with the results, especially for a weekend\nproject. It’s breathed life back into the game for me, not only having a\nbetter experience running it, but also that I can trivially bend the game\nto my will in the ways I dreamed about. A few hooks in the right places\nshould open the game to easy modding, but I’m more engineer than modder.</p>","headings":[{"level":3,"text":"Implementation details","id":"implementation-details"},{"level":3,"text":"Endless possibilities","id":"endless-possibilities"}]}}