Rust has a fantastic and well developed universe of 3rd-party crates which will help you develop almost any application, right up until they suddenly won’t. Here are four ways in which you will be suddenly and deeply frustrated while learning this exciting new language.
Weak typing is a documentation-specific feature.
One of the unique aspects of Rust is the subtle but specific control over the movement of data under the ‘borrow’ system, which provides tough but fair oversight of access to information. To work effectively in this system, you need to know all about your data types, their capabilities, their restrictions, their lifetimes and much else — especially if you want to pass them into and out of functions.
Enter the idiomatic documentation style, in which you’d be forgiven, encountering the language, for believing that the whole thing was weakly typed all along:
Taken (with apologies) from the rand crate book, the most popular rust crate.
Members of the community will be happy to inform you that compiler error messages are the fastest source of correct type name information.
2. The new version is completely different and we’re all using it now.
Enjoying all the conveniences afforded to you by this popular crate? Well, watch out, because that’s the deprecated 0.15 package.
That’s right, despite being at the end of a 32-crate long chain locking you in to 0.15, main development — and somehow a bulk of users — are focused on 0.16 now.
The API is fundamentally incompatible, usually due to the start or end of support for a platform you’re not interested in, and all of the dependencies are partially updated — if at all.
3. “I have made excellent progress on this in a private branch seven months ago”
Oh no — you’re using your fancy new Rust crate, but it won’t interop with another similarly fancy API or library that you’re also using! In fact, they’re mutually exclusive.
Fortunately, there’s a GitHub issue for tracking this already, and some smart young grouse is making very perceptive comments and hinting that the solution is just around the corner — seven months ago, with radio silence and the fork set to private ever since.
4. You shouldn’t, and therefore you can’t.
Code, colleagues and convenience will often contrive to back you into a corner on some proposed feature or extension. It’s ugly, but there’s no other way to do it without necessitating some fundamental restructuring of your application. You sigh as you open your box of ugly hacks and set about patching it up.
Unfortunately, you hit a blocker — some Rust package you depend on is complaining loudly about the exact thing you’re intending to do, and is blocking the build. Time to take to the airwaves, and search social media to see if there’s any quick way around this one. The replies comes quickly and in force: “you shouldn’t, and therefore you can’t”. Whether or not there’s a technical barrier to solving your problem, there’s an organic barrier that will be just as effective. Computers are machines of infinite flexibility, but that may not hold for your fellow coders.
(Double points if there is a workaround available in the interface, but it’s been unmaintained to the point where it no longer works correctly.)
A disclaimer, of course, that this list is at the very least wildly unfair on the good work usually done for free by package maintainers and the community around Rust, whose contribution to problems I’ve needed fixing absolutely outweighs their contribution to problems that have made me swear loudly.
This essay is an accessible version of an in-browser game available here.
I don’t like players.
Or, to be less misanthropic, I don’t care for players. They do their thing, and I do mine. I make my games like I built sandcastles as a child.
Can you come play in my sandcastle?
Maybe, sure, once it’s done.
Once I’ve drawn the line in the sand that means “the part where this gets made is over and the part where it falls away into oblivion has started”.
Sometimes of course, I am a player. I try to play appropriate respect to the people who make the games I play, which is maybe to compliment them on their artistry if there’s an appropriate venue to do so… probably not on twitter… and remain silent the other 99% of the time. Nothing more perverse than taking someone’s art and offering them unsolicited technical advice.
Lots of people in games have a community; I wish them all the best. But I have a community, and it is not in games. To have a community in games I’d have to compromise my participation in communities elsewhere and I’m not willing to do that. Like most people, I think, I’m already anxious enough that I’m failing to meet my existing social commitments. I’m not willing to take on the burden of more friends. Sorry. I could get a job making games. But I won’t. No apologies there.
Without players, and without a community, and without a commercial interest and promotion and professional marketing and all that guff… There aren’t many venues through which people to play the games I make. I can expect a polite level of interest from my friends, like when they talk to me about climbing or rowing or filmmaking or cooking or running. They might have a look, as a curiosity. Or they might not. Their interest is not my interest.
For the most part, this does not bother me.
I like the part where I build the sandcastle, and if I depended on other people’s validation of my art (at least in this instance) then I might act differently. But I don’t, and I won’t. It just seems so odd, to make a game that is not to be played. So much so that I’ve taken some time out and made games that can be played, just to make sure I could. But I feel just as unfulfilled in either instance. Giving those games to people, to play them, is nerve-wracking.
When I’m at home alone, just me, I dance. I put some music on, whatever I’m feeling like, and I just slam around. Back and forth, up and down, in different rooms. Or I put on some movies I don’t think anyone else would be interested in, and watch three in a row.
Or I sing, and record myself singing, then delete the recording. These activities have never felt less than complete. Which I not to say that I don’t appreciate participatory art; I’ve made videos, I’ve directed a play, I’ve done things which are collaborative. They’re fun. But I make my games for me, even as they pull away from me. They demand of me that I learn the skill of marketing and networking and twitter, and they press me against this horrible flat surface where I read about… how the steam storefront is changing and what that means for wishlisting… or else how there are game jams happening this weekend. They even have game jams for people who make games alone. But I don’t want any of that. I like to make my games, by myself. Even now, I’m writing an essay so I can release an essay, in the exact space where I make my game and do not release my game. It’s just how it is with me.
Can I make games alone if I don’t like players? I guess, I can.
This article transcribes a video essay available here, titled “Cats is a triumph of the cinematic form.”
Cats, the 2019 movie directed by Tom Hooper, represents countless hours of work-power, in likely miserable conditions, assembling what is unmistakably the world’s highest budget work of furry cinema.
Hooper, fresh off the success of the Les Misérables movie adaptation, which I hate, likely had a free reign to interpret as he wished the Andrew Lloyd Webber musical CATS, itself a loose adaptation of T. S. Elliot’s poetry collection “Old Possum’s Book of Practical Cats”. The Webber musical is his standard campy fare, lurid face-paint and costumes in the fashion of Joseph and the Amazing Technicolour Dreamcoat or Phantom of the Opera, two other musicals which had their own dubious route to the big (or small) screen.
Easily the least interesting parts in Cats are where Tom Hooper concedes to the style that won him critical acclaim with Les Misérables and holds a steady close-up of an impassioned face singing a showstopper. Where he’s persuaded away from it, we get Rebel Wilson tearing the head off a cockroach with a human face, Jason Derulo showering himself with milk as a rake of female cats watch in awe, and a succession of cats improbably wearing human clothing seemingly only for fetishistic effect — an even more convincing case for Tom Hooper being prevented from filming close-ups than anything in Les Misérables. Macavity, the cat devil, is introduced with a Batman-like sudden disappearance once he’s off-camera — but the next time he appears he really can teleport and does it constantly for the rest of the film.
The film is determined to see any suggestion that there’s a sexual undertone off at the pass. Over the first thirty minutes, cats present their groins, arch their thighs, tangle round each other almost deliberately so that there’s as much contact with their Barbie-doll under-sections and chests as possible. Every cat is wearing a human-sized collar. Rebel Wilson’s cat bends her tail forward between her legs and swings it like a windmill. Cats wear fursuits, gorge themselves on food and dive into trash cans to rub themselves in waste. When a male character hits a high note, there is a conversation about neutering where Rebel Wilson makes a chop-chop motion with her fingers. As mentioned, Jason Derulo pours milk into his own mouth as he lies back on the floor. The cats devour other, smaller humanoids with a smile and a wink. During his song, there is a lingering shot where Jason Derulo has a furry cat foot inches from mouth with a furry cat foot. By the time three cats are cavorting on a bed together covered in feathers you’re absolutely numb to it, and the film proceeds to get into the plot — and even the plot involves all the cats getting high, having a PG-rated orgy, then lying about groaning for a good minute. Idris Elba’s character is fully dressed for the majority of the film, just so that when he appears sans garments in the climax, you can’t escape any suggestion, Idris Elba is nude now.
As critics have mentioned, the film makes minimal effort to explain who anyone is or what they’re doing. They’re cats, they’re having some kind of event, most of them are going to sing one song, the word Jellicle is involved, get with the program. The cats sing an entire song about the importance of the protagonists’ “real” cat name, but we never find it out. It’s just not for us to know. One member of the main cast is never properly introduced and doesn’t have a song. At one point I thought he was singing about himself but he turned out to be singing about a cat dressed as a male stripper.
Which is fine! It’s fine.
Much of the prerelease buzz around Cats focused on the uncanny appearance of the characters, human faces rotoscoped by hand onto almost-matching CG bodies. What the previews did not reveal, is that the rest of the film compensates for this effect by being equally uncanny, unsettled, and unmoored from conventional notions of filmmaking. The structure of Cats — individual vignettes about the mercurial nature of individual Cats — is forcibly bookended by an overarching plot in which Francesca Hayward’s character, ‘Victoria’ is abandoned by her (full scale human!) owner, such as it were, and falls into the company of a gaggle of cats who immediately begin a chain of often unintelligible songs which continue end-to-end for the rest of the film, save for brief interruptions by the antagonist, Macavity, played by a gurning, scenery-gnawing Idris Elba. The cats hold a yearly competition, we are repeatedly told, where the victor receives a ‘second chance at life’. This plot structure being clamped around the more freeform nature of the musical adds a terrifying air of inevitability to proceedings, and makes the eventual awarding of the prize to Grizabella feel less like the triumph of good nature and compassion and more like “oh crap, gotta foist this ticking bomb off on someone before Idris Elba gets back. The sense of unease and the unknown is shared between the audience and Victoria, but it leaves the more carefree earlier songs feel like they’ve been shot through the sights of a gun. “Stop dancing!” you want to scream at the screen, “Idris Elba is murdering you!”
Between this and the borderline-violent reaction unnamed cats have to the down-and-out Grizabella every time she appears, cat society is deeply unsettling, and that’s before the Taylor-Swift-penned addition to the songbook “Beautiful Ghosts” has appeared, with the haunting refrain “The memories were lost long ago, but at least you have beautiful ghosts”.
Perhaps to provide cover for some less prioritised effects shots, the camera often appears as if in the hand of a drunkard, dipping and rolling with the music in a way that almost induces illness, especially combined with how, over the course of the film, the scope of the visuals slowly narrows and a set of basic images recurs: The theatre door, the bolted milk-parlour, Grizabella in the street, the graveyard entrance, Old Deuteronomy beckons, repeat. One of the most striking visuals, a stairway to heaven summoned by Macavity when he seeks to force Old Deuteronomy to grant him a second life, does not reappear at the denouement. Instead, Grizabella is loaded into a balloon and floated off into the sky.
The protagonist sings of dancing with ghosts; Grizabella is “saved” by being jettisoned into the sky and forgotten. The cats who are kidnapped by Macavity throw Ray Winstone, of Noah fame, into the Thames to drown – and cheer while they do it. Taylor Swift’s cat disappears halfway through the third act. It’s hard not to come to the conclusion that the film is telling us that the cats are in hell, or at least in purgatory. There is a cat devil, but there is no cat god.
Let me be clear about what I am saying: this film is an absolute triumph. It’s utterly bizarre, obeys only its own logic, and I would have eagerly watched another hour of it. Go and see this film.
Please see Cats.
The image of Old Deuteronomy stretching her leg in this article is taken from Twitter user @MrMichaelSwartz’s video.
Using static databases and simple code generation to describe almost-dynamic game content.
I’m a solo indie dev working on my magnum opus of undisputed genius, _space_train. The daily grind of handling all aspects of game development is my burden, except when I’m not doing that because I have a regular job as a software developer instead. The major flaw with _space_train is that there’s no compelling reason to play it, and that that will continue to be the case for the foreseeable future. Nonetheless, if you want to follow development and watch as I slowly descend into madness and ignominy, it has an itch.io page here with a downloadable build and a Twitterhere.
I had an issue building _space_train, my magnum opus of undisputed genius. The path to complex user interactions lay in the direction of adding ‘content’ for prospective users to engage with. In material terms, this meant adding more of the things that people do in the game: items to pick up and use. The problem was, adding new items was proving a surprisingly laborious task for me, the developer. Items in _space_train are represented by unique id numbers associated with an entry into a centrally managed map which has an id, a type, and a ‘display modifier’, a bitfield which specifies the appearance. The list of possible item types is represented with an enum, and a separate mapping exists to convert between the enum value for each type name and the string name for each type — the string value being necessary for accessing external resources for each item type, specifically Lua scripts which say what they do in various scenarios.
Adding a new item then, means adding both to the enum, and then to the name map, the name of the new item. In addition, over on the client side, the item type then needs to be associated with coordinates into the item texture, represented in another enum. All this before any actual material properties of the new item can be expressed!
A player standing by a handful of items in _space_train.
The elephant in the room is the possibility of loading and representing item types at runtime. This would necessitate separating items into some extra-compilatary zone where they can be manipulated distinct from the game code, all together all in one place. This was appealing in some ways — it would remove business data from the scrappy C++ engine I’ve insisted on building and relocate it, in a potentially more manageable format. I didn’t want to give up, however, on the ease of referring to item types directly in code, or take on the overheads of runtime look-up.
Around a year ago, I became aware of a software development tool called CastleDB (www.castledb.org), which appeared to do something to do with static data. The website described it thus: “CastleDB is a structured static database easing collaboration.”
Structure sounds good. Static sounds good. Unfortunately there’s only me working on _space_train so the collaboration might go a little under-utilised, but I was still excited.
Unfortunately, at the bottom of the page, castledb.org also says this: “CastleDB was created using the Haxe technology, it also allows some Haxe-specific integration.” I’ve heard of Haxe, and the website for it only really confused me more as to what it does, I’m aware it’s some sort of web-development-y thing. And I myself, a terrible C++ programmer, don’t understand the first thing about it — or any other webdev library. Thrown into confusion like this, unclear over whether or not CastleDB was something only web developers got to use, I did what any good programmer ought to do: I left the tab open for a full year and skim-read the page again, once every other month.
Eventually, I decided to go one step further: I downloaded the damn thing. Inside the zip there was an index.html, which loaded into a blank spreadsheet with buttons that didn’t work and an error in the console saying “CONSOLE ERROR HERE”. It turns out CastleDB is bundled as some kind of self-hosting web executable, and I was supposed to go against years of instinct and open cdb.exe rather than the enticingly-named index.html. Never grow complacent.With CastleDB opened properly, I found that it was actually exactly what I wanted: for want of a simpler phase, it’s Excel but not dynamic. It’s phpmyadmin but not php or mysql. It’s hand-editing JSON but without any hand-editing JSON. You enter static data in a familiar-ish interface (minor gripe — copy and paste doesn’t work on MacOS, but I’m narcissistic enough to enjoy retyping my own work) and it comes out in JSON. This was the start of something good.
What I wanted, was to enter data using this convenient interface, and have it represented in code for me to use when designing game elements (in theory the bulk of game development; in practise I merely add more engine features and release nothing). This necessitated some kind of transformation of the data into code, either at compile time or at runtime. As discussed earlier, I’m loath to defer this process to runtime for several reasons, most of which boil down to wanting to pretend my program is less complicated than it is. If elements are loaded at runtime, then all references discovered while debugging are contingent on that load, and it’s harder to have good instincts about what is out of place or unusual. So I wanted this to happen at compile time.
The missing link here for C++ development specifically, is some kind of all-constexpr JSON processing library that can automatically infer data structures from some input. I am not the person to write that library though, and decided to make do with some homegrown codegen.
Codegen is the art of code which produces code, and often leads to some of the worst abominations of programming imaginable. All the personal terribleness of the programmer who wrote it, combined with a computer’s indefinite ability to spew vast reams of procedural content. Nonetheless, codegen has a proud history in games: in the Wolfenstein 3D Black Book, Fabien Sanglard describes how iD used codegen to produce (and patch!) code for transformation tables for sprites at distance at runtime, in order to minimise the size of the executable shipped. If it’s good enough for shooting Nazis, it’s good enough for me.
JSON was originally invented to serve as a serialisation format for Javascript, so I immediately decided the best tool for this job would be Python. Python has a first-class JSON loading library, and very simple string manipulation functions (compared to working directly in C++ for this). Using a Python script to write some simple C++ types and functions into a header and cpp couldn’t have been simpler, and I very quickly had a working enum class generated, included and compiled.
My simple database of space-tomatoes.
From this quickly thrown-together table of existing content, a handful of Python lines in the fashion of the ones below:
output_h.write("""
enum class list { """) for item in item_db_items: output_h.write(" "+item['type']+",\n") output_h.write(""" }; """)
Were able to throw out a quick enum:
enumclass list { none, tile, ticket, food, screwdriver, shovel, terminal, pickaxe, access_card, hat, corpse, fuel_brick, mug, oxygen_mask, urine, };
My enthusiasm for this approach quickly snowballed. Not only was I now generating the enum and the static constexpr map from the JSON file, I added a column for the item descriptions, making them easy to read altogether and also amend, and also for the short descriptions used when the items are hovered over.
Then I went one step further and moved a function from the engine client that selected an image to pair with each item, and had that generated from the JSON too. CastleDB has built in support for (varyingly-sized) tiles and will handily display them inline for easy glancing. I didn’t need the relative path to the image, both because resources in the _space_train engine come from specific named textures, and because the directory structure from compile-time has changed by runtime, but were that not the case it would have been easy to pull it out of the provided ‘tile’ data type in CastleDB.
With this under my belt, I drove further forward and converted the floor tile types and image mappings too, as well as room bounds (which are done under the hood in an extra layer of tiles. Three whole compile units are now being generated! I made myself feel extra professional by abstracting common functionality, mainly related to the opening of files, into a python module called codegen.py. I refrained from getting too smart and making a special python class with scoped constructors and destructors which would function to emulate C++ namespaces and other cleverness like that, because down that road lies madness and the aforementioned template-based constexpr JSON library.
Since adding the codegen functionality to _space_train I’ve identified several other candidates for static codegen, including a table of sound effects and a table of background music entries. If you made it this far, thank you for reading and I hope you enjoyed my terrible programmer jokes.
If you want to look at the codegen Python in more detail and send me a message about how bad it is, it can be viewed in a pair of gists here (codegen.py) and here (item_codegen.py).