Making a Screeps Client in Unity3D

Hello screepers! A couple months ago I started working on my own Screeps client, just for the heck of it. I’ve shared gifs and people were curious, so I thought I’d tell the story.

Is this your first time hearing about Screeps.com? You should check it out. If you are a programmer and you enjoy strategy games you will be in heaven, there is no other game like it. If you are interested in learning to program, it is an engaging way to develop and improve your skills. I’m just a humble player and not affiliated with Screeps.com.

A Console in Windows

This project started as something much more simple than a client,  it was just going to be a console.

I already have a favorite console that I use in Linux. I like to have it running when I’m doing other stuff, watching it is something similar to watching a lava lamp.

However, most of the time when I am working, I need to be in windows. All my attempts to get this tool working in Windows have only produced failure and swearing. I’m sure there are much better ways to solve this problem, but my bright idea was to try to make a console with Unity3D, which I am trying to learn.

Screeps.com has not published very much information about their endpoints. The official documentation states:

Many third party programs are built using unofficial APIs and may stop working at any time.

Still, enterprising players have put together some very helpful resources for anyone considering making a tool. The most useful endpoints are included there, and whatever is missing I was able to find by snooping around with the browser dev tools. I also pestered said players with many a question and they were excellent in putting up with me.

I decided to try and implement the equivalent of node-screeps-api in C#. Having never worked with HTTP requests or websockets, this was a challenge. But through trial and error, and with a very high error-to-trial ratio, I was able to produce something that works. I’ve kept this part of the code encapsulated so that it could be re-used in other C# screeps projects.

After that was out of the way, putting together a basic console was a piece of cake.

From Console to Client

Now I faced a new, much more serious problem. I had a fancy new way to use the unofficial screeps API in Unity3D, and so many endpoints were unexplored! I decided to see what it would take to render terrain. It was surprisingly easy! The next day I had this as a proof of concept:

So now I could render terrain, the next big leap would be rendering room objects. The main thing I was lacking was a set of 3D assets. Now, I am not a 3D artist by any stretch of the imagination. Making anything more complex than a cube will make me furrow my brow in an unflattering way. I wasn’t even sure this was going to work, so rather than put a lot of time into making my own assets for this early prototype, I shamelessly scavenged them from the Asset Store and other places that publish 3D models under a creative commons license.

I also needed to figure out how  to use the stream of data delivered through the websocket to render objects and their behavior. To put it briefly, the first tick that you encounter an object you are sent all of its properties/values as JSON. Each subsequent tick you are given only the values that have changed, the delta. The client needs to create its own representation of the object and update it as needed.

This was an interesting challenged and I learned a lot along the way. The next day I had this:

Multiple Rooms

So far, everything had worked much better than expected. By now I was imagining all the possible directions I could take the project. One limitation of the official client is that you can only view a single room at a time. Drunk with power, I decided to see what multiple rooms would look like.

It worked, but I noticed the FPS took a huge hit. I was fairly certain that this is because of how I’m rendering the terrain. Each element of terrain is a single gameObject. This means that in order to render the terrain for a single room with 50 positions in each dimension, it would require 2500+ separate objects for the terrain alone! Obviously that will not be very efficient.

A much more efficient way would be to start with a single plane and deform it as needed. I also needed to be able to color the terrain to make the distinction between plains/walls/swamps. Rather than deal with generating a texture map which would look bad unless it was an extremely high resolution, I used a single plane for each terrain type. The plains-plane is at the top with the swamp-plane and wall-plane just a smidgen below it. Together they make a sort of plane-sandwich or plane-lasagna, whatever sounds more appetizing:

As I’m iterating over the room terrain, if I encounter a position that has a wall, I poke up the vertices for that part of the mesh so that it appears above the plains. I use the same tool to deform the swamp plane, I just don’t poke it up quite so high.

It worked like a charm! I could now render the terrain for as many rooms as I wanted without experience a loss in FPS.

It bears mentioning that I love the art style of the official client, the simple 2D graphics are a big part of its charm. But it was starting to become apparent how a 3D environment could add something special. I was learning a lot along the way, so I decided I would run with it.

Making Creeps More Creepy

The model I was using for creeps made it look like an entirely different game, so that became my next target. I had to ask myself an important philosphical question, what would a creep look like in 3D?

I went through many different prototypes to try and answer this, but I settled on something quite simple. I just chopped the bottom half off of an icosohedron and made it flatter. Another major element missing was the player badge. Player badges are defined in SVG/XML, and it was difficult finding a C# library that would work with the dated version of mono that is used by Unity3D (.NET 3.5 equivalent). Fortunately I found one from 2008, on about the 3rd page of google results (shudder). I also had to hack together some C# code that would implement the algorithms for generating the SVG/XML that was originally in Javascript.

Amazingly, it worked! Here is a side-by-side with the official client. It is worth noting that this was when the WebGL renderer was quite new and there was a bug that incorrectly rotated the badge in the official client. It made me feel better about all my own bugs.

I sort of love the way these turned out. They look like colorful little Go pieces.

I still needed to render the creep body parts. After trying out a few crazy ideas…

…I decided on something much more familiar:

It is worth noting that eventually we will need to find a new solution for converting SVG/XML to a texture unity can use. The solution depends on a windows library, which makes it complicated to do builds for other OSes. Rendering badges was the hardest thing to figure out so far, I’m just not quite ready to re-tackle that, yet.

UI Design and Creep Behaviors

The Screeps Warfare Championships happened to be underway, and it was my first chance to actually use Screeps3D. One major missing piece was some sort of UI with which I could view the properties of game objects, so that became my next mission.

In order to view an object’s properties we would need to have some way to select it. It was around this time that trebbettes joined the project, and he decided to write a selection tool. We thought it would be cool to be able to select more than one object at time. His solution worked perfectly, it was possible to select multiple objects by using ctrl+click or doing a box select.

This video shows our progress with the object models. One by one, we’ve replaced all the assets we borrowed under the creative commons license, so they are completely original. They are very low poly and simple, but they are much more familiar. Hopefully they have some of the same simple charm held by the official Screeps art.

Another thing we worked on together were creep behaviors. So far creeps could move around but not much else. By adding beaming and bumping they became much more fun to watch.

Map Maker, Map Maker, Make me a Map

Playing screeps, you easily spend just as much time looking at your map as you do your rooms. One thing that was striking to me was how the room view could already look a lot like the map view just by zooming out.

Adding in the 3D perspective allows for a game viewing experience that is unique to the Screeps3D client, sort of a seamless transition between room viewing and map viewing.

The Current State of Affairs

So that pretty much brings us up to the present! I’m fairly proud of what we’ve been able to put together over the last couple months in just our spare time. The big question is, will it ever be released? Magic 8-ball says: all signs point to maybe.

The biggest hurdle will be finding a way to authenticate with the public server. Recently the Screeps devs introduced auth tokens, which are now the official way to connect to the servers for 3rd party tools. We’ve already implemented this way to authenticate in Screeps3D, but there is a bigger problem. These tokens have rate limits, which means you can only access certain endpoints a limited number of times per hour. This is important to keep 3rd party tools from abusing the api and drawing too many resources.

However, they do not work very well for a client. The limits were designed for automated tools like stats-checking programs which can be easily configured to make a fixed number of requests within a certain time frame. Since a client’s data use will be driven by the player’s interaction rather than an automatic algorithm, staying within a fixed limit becomes much more challenging. For example, scrolling around the map will cause you to meet the limit of 360 terrain requests in a very short time. Each sector has 100 rooms, so just zooming out and looking in each direction, you will max-out in just a few seconds. There are ways to mitigate this like caching terrain client-side (which we already do) but unfortunately this won’t be the only example.

Even the devs have acknowledged that rate limits are inherently difficult for a client, and they’ve suggested authenticating in the same way that the official client does which will involve completing an invisible reCAPTCHA periodically. Invisible reCAPTCHA is web-tech, and It isn’t clear how feasible this will be to implement in Unity3D. It would also mean bypassing the rate limits which serve an important purpose, so it will be even more crucial to make sure Screeps3D uses the server resources responsibly.

Still, I’m fairly certain there will be a release someday. At the very least, it will still be possible to use the client with private servers which are not rate limited. Not being able to use it with the public server would take a lot of wind out of the sails, but I’m sure it will get done eventually.

It is even more likely to be finished if more collaborators jump on board. If you are a Unity3D whiz or you’d just like to learn, please join! It is also being developed under the MIT license so there is nothing stopping someone from forking the project and taking it in any direction they want.

(If you poke around the repository (develop branch) you’ll be able to find some pre-alpha builds. These aren’t exactly intended for public consumption and I don’t recommend them unless you know what you are doing.)

If we ever do a release, it will be dedicated to the good folks in #client-dev on the official Screeps slack. This project wouldn’t be anywhere close to what it is without their advice and encouragement. If you have any interest, join us there!