<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://felixjones.co.uk/feed.xml" rel="self" type="application/atom+xml" /><link href="https://felixjones.co.uk/" rel="alternate" type="text/html" /><updated>2025-07-06T16:58:24+00:00</updated><id>https://felixjones.co.uk/feed.xml</id><title type="html">Felix Jones</title><subtitle>The blog of Xilefian.
</subtitle><author><name>Felix Jones</name></author><entry><title type="html">My Pokémon ROM Hack</title><link href="https://felixjones.co.uk/2025/04/30/pokegreen.html" rel="alternate" type="text/html" title="My Pokémon ROM Hack" /><published>2025-04-30T00:00:00+00:00</published><updated>2025-04-30T00:00:00+00:00</updated><id>https://felixjones.co.uk/2025/04/30/pokegreen</id><content type="html" xml:base="https://felixjones.co.uk/2025/04/30/pokegreen.html"><![CDATA[<p>Yes, yes even I am guilty of picking up side projects when I have a side projects going on.</p>

<p>At least this one is in the Game Boy family!</p>

<hr />

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/side_hack.png" alt="Screenshot of the original Pokemon Game Boy game, but it has been hacked to feature both a female trainer, and Game Boy shaped wild Pokemon. The text box reads: Wild SIDE'HACK appeared!" width="640" />
</p>

<p>A couple of months ago I was ill with a cold, and I did what most people do when they have a cold: They browse Reddit.</p>

<p>I stumbled upon a few posts in the Game Boy subreddits from Redditors showing off their custom made “Pokémon Green” cartridges.</p>

<p>For those not in the know: The original Pokémon games released in Japan in 1996 as Pokémon Red and Green, so these custom cartridges were an attempt to restore what is often seen as a lost Pokémon game.</p>

<p>Somehow my cold-stricken head decided to lead me into ordering all the materials I would need to create my own “Pokémon Green” cartridge.</p>

<h1 id="if-a-thing-is-worth-doing">If a thing is worth doing</h1>

<p>This isn’t the first time I’ve come across custom Pokémon cartridges, but I’ve never had a desired to make my own.</p>

<p>A lot of the times it is individuals creating custom carts to avoid paying the inflated prices for legitimate, original games, but custom Green cartridges are more interesting.</p>

<p>The Japanese releases of Red and Green have differences to the international Red and Blue, not to mention that 1996 is before Pokémon made its international debut, so there was no international branding associated with Pokémon. Combined with the fact that there was no international “Pokémon Green Version”, there’s a gap to be filled.</p>

<p>Check-out this <a href="https://www.youtube.com/@BoundaryBreak">BoundaryBreak</a> episode that explores some of the differences:</p>

<iframe width="100%" height="400" src="https://www.youtube.com/embed/RMZa3Eh-6ug?si=2wtFXC_8ST9AisrR" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<h2 id="it-is-worth-doing-well">It is worth doing well</h2>

<p>Something I’ve said for a long while regarding retro game projects is that I believe they’re most successful as art pieces, a love letter to a bygone era in gaming.</p>

<p>If I were to make a retro game I would want to make a physical cartrige, a box, and a manual to “complete the package” (throw in a poster or something, too). I imagine most people would get enjoyment out of the high quality physical goodies, but as a game developer I get enjoyment at the thought of high quality software being amongst the physical goodies.</p>

<p>Now that I have bought into a high quality Pokémon Green display project, I thought I should follow through on my standards and make a high quality Pokémon ROM hack to go with it.</p>

<h1 id="pokémon-rom-hacks">Pokémon ROM hacks</h1>

<p>Pokémon is quite famous in the ROM hacking scene, specifically the fact that many of the classic games have decompilation projects that make producing ROM hacks a cinch.</p>

<p>The pokered project is available on GitHub https://github.com/pret/pokered</p>

<h2 id="shin-pokémon-green">Shin Pokémon Green</h2>

<p>Whilst the US release of Pokémon Red and Blue have been decompiled, the original Japanese release of Red and Green have not. So I needed a base: Someone who has restored the Japanese content into the pokered project.</p>

<p><a href="https://github.com/jojobear13/shinpokered">jojobear13’s shinpokered project</a> does exactly that…And more!</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/animfadeboxsmall.gif" alt="Animated GIF fading between the different box arts of the Shin Pokémon project." width="300" />
</p>

<p><a href="https://github.com/jojobear13/shinpokered?tab=readme-ov-file#summary">The summary</a> lists some of the “Additional Master features that go beyond engine modifications and fixes”, and a lot of these go quite far beyond what the original games provide.</p>

<p>I didn’t actually want these additions, I wanted to make something that feels more purposefully pure to the Japanese release of Green. A sort of “What if Pokémon released internationally a year earlier?”.</p>

<p>Luckily the project provides a <a href="https://github.com/jojobear13/shinpokered/tree/lite">lite branch</a> that only includes fixes and none of the “Additional Master features”.</p>

<h1 id="are-you-a-boy-or-are-you-a-girl">Are you a boy? Or are you a girl?</h1>

<p>Shinpokered is quite a well organised project: It’s possible to configure it quite extensively from just the makefile.</p>

<p>I noticed that it even keeps some of the code and assets from the “Additional Master features”, in particular the macro <code class="language-plaintext highlighter-rouge">_FPLAYER</code> enables the code and assets for a female trainer.</p>

<p>I decided to break my rule of “What if Pokémon released internationally a year earlier?” and add in an option to select a girl player character.</p>

<p>I feel this can still be in the spirit of a “What if” because a female trainer for that generation did exist in the manga, as well as on the cover of the Japanese strategy guides, as covered in this video by <a href="https://www.youtube.com/@TheObsessiveGamer">The Obsessive Gamer</a>:</p>

<iframe width="100%" height="400" src="https://www.youtube.com/embed/xSeA3MzcoGY?si=EuiTWvxf2zBAOWK4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>

<p>Let’s take a look at Shinpokered’s female trainer:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/bgb00026.png" alt="Screenshot of the name entry screen for shinpokered, with the female player sprite displayed. The character is clearly an edit of the boy sprite." width="160" />
<img src="https://felixjones.co.uk/assets/pokegreen/bgb00025.png" alt="Screenshot of the starting home in shinpokered, with the female overworld sprite." width="160" />
</p>

<p>Unfortunately this character is not the legendary Game Freak character, but is an edit of the boy trainer sprite:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-9.png" alt="Screenshot of the name entry screen for pokered, with the original boy player character." width="160" />
</p>

<p>I looked around at other implementations of playable girl trainers, and I feel most of them miss the mark. Many of them implement the Leaf character from the Game Boy Advance games, some of them do implement the “lost” female trainer but with spritework that feels closer to modern Pokémon art styles than the original Game Boy art styles.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/4205screenshot2.png" width="160" />
<img src="https://felixjones.co.uk/assets/pokegreen/yellowlegacy.png" width="160" />
<img src="https://felixjones.co.uk/assets/pokegreen/8100screenshot3.png" width="160" />
</p>

<p>It was becoming clear that I needed to introduce yet another playable girl ROM hack so I could create the character that I was looking for in my custom Pokémon Green ROM hack.</p>

<h1 id="finding-the-style">Finding the Style</h1>

<p>I noticed that the games feature multiple sprites for the rival trainer as the player progresses from the start of the game, all the way to facing the rival as the League champion in the final battle.</p>

<p>This provided a gradient of art styles going from a more “junior” starting trainer, an intermediate, and then the champion. I decided that the player is somewhere in the middle as an “intermediate”, so that was the style I was aiming for.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/sheet.png" />
</p>

<p>Looking back, my first draft reminds me of some of the early Pokémon Gold “dealer” sprites from Game Freak.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/lineup.png" />
</p>

<p>The pose was inspired by this panel from the Pokémon manga (the “Yellow” arc):</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/Green_Y_chapter.png" />
</p>

<p>When working on digital artwork I use the “mirror” trick where you flip the image you’re working on to gain a fresh look at what you’re working on. It helps with identifying perspective errors, but also results in images that look good even when mirrored, and I ended up keeping the mirrored direction.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/progress.gif" />
</p>

<p>There was a moment when I realised this lacked any “main character energy”, which is why I added the Pokéball earrings to the character (as shown in the Yellow arc of the manga).</p>

<p>I requested feedback from <a href="https://bsky.app/profile/sarahboev.bsky.social">@sarahboev</a> (whom I originally reached out to for this project, before taking it on myself) and they kindly pointed out that the dithering work on the hair is not characteristic of the original Pokémon games: notice that almost all trainer sprites use solid blocks of colour for the hair, and dithering is only used for textiles such as clothing.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/hair.png" />
</p>

<p>Here’s what the final sprite looks like on the trainer screen:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-17.png" />
</p>

<h1 id="battle-sprite">Battle Sprite</h1>

<p>This one was more straight forward than the front sprite, although I did end up with something that looks more fitting for the second generation of games, rather than the first.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/back.png" />
</p>

<p>I may have gone too far with the anti-aliasing, and I brought the character closer to the viewer which probably makes it feel more modern. Regardless, I noticed that the 2x resolution psuedo depth-of-field for generation 1 backsprites makes these details forgivable.</p>

<p>The pose is partly inspired from their appearance in the Gold, Silver &amp; Crystal arc of the manga:</p>

<p align="center">
<img height="415" src="https://felixjones.co.uk/assets/pokegreen/Green_GSC_chapter.png" />
</p>

<p>I did give up with rendering the gloves with the excuse that sprite consistency wasn’t a thing even with Game Freak.</p>

<h1 id="overworld-sprites">Overworld Sprites</h1>

<p>These were probably the most difficult sprites to work with as the canvas size is reduced to just 16x16 pixels, and the amount of colours available is reduced to 3.</p>

<p align="center">
    <video controls="" width="100%">
        <source src="https://felixjones.co.uk/assets/pokegreen/overworld.webm" type="video/webm" />
    </video>
</p>

<p>I’m not 100% happy with the result.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/walk_down.gif" />
<img src="https://felixjones.co.uk/assets/pokegreen/walk_up.gif" />
<img src="https://felixjones.co.uk/assets/pokegreen/walk_side.gif" />
</p>

<p>But I am happy versus my other attempts.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/sprite.png" />
</p>

<p>Adding the earring to the side sprite very much helped tie the sprite back to the trainer graphic, however I was unable to find a good way to show the earrings in the up/down sprites.</p>

<p>Another feature that helped add depth was the light “shine” on the hair. I was holding off from doing this, but seeing a similar hair “shine” on the Pokémon Center attendants convinced me to try it.</p>

<p align="center">
    <video controls="" width="100%">
        <source src="https://felixjones.co.uk/assets/pokegreen/heal.webm" type="video/webm" />
    </video>
</p>

<h1 id="diploma-screen">Diploma Screen</h1>

<p>Shinpokered uses the front sprite for the Diploma screen:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-11.png" />
</p>

<p>The original code actually pulls this image from the title screen trainer graphic</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/player_title_green.png" /> <img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-12.png" />
</p>

<p>Shinpokered does not display the female trainer sprite on the title screen, which is something I wanted to change.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-10.png" />
</p>

<h1 id="titlescreen">Titlescreen</h1>

<p>Now that I created a unique title screen sprite for the diploma I should use it on the actual titlescreen!</p>

<p>But first, the logo:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/logo.png" />
</p>

<p>Changing the logo is probably controversial, however I wanted to keep the feeling of a “Pokémon Green” release, but without reverting to the Japanese logo.</p>

<p>This might look bland in comparison to the official international logo, but I did borrow the look and font from the same Japanese media that the female trainer originally appeared in:</p>

<p align="center">
<img height="400" src="https://felixjones.co.uk/assets/pokegreen/guide.webp" />
</p>

<p>And I am happy this captures the spirit of “What if Pokémon released internationally a year earlier?”</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-13.png" />
</p>

<h2 id="girl-titlescreen-sprite">Girl Titlescreen Sprite</h2>

<p>I struggled with this sprite, and I’m still not entirely happy with the end result (specifically the leg pose)</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/diploma_sprites.png" />
</p>

<p>Here’s what I settled with:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-14.png" /> <img src="https://felixjones.co.uk/assets/pokegreen/player_title_f.png" />
</p>

<p>The pose is from this image of the character from the Pokémon manga:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/GreenAdventures.webp" />
</p>

<p>See how I replaced the Pokédex with an original Game Boy. When I saw the manga image I thought “did the Pokédex even have its design in 1996?” - the Pokédex sprites in Oak’s lab are re-used book sprites and mentions pages</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/bullshot.png" />
</p>

<p>I ended up looking through the original Japanese instruction manuals and other media at the time of the release and found no artwork of the Pokédex as we know it.</p>

<p>I considered changing the Pokédex out for a book, a Pokéball, or nothing at all - but I like the personality that I’ve given the girl character (in contrast to the very stern-looking boy character), so I tried throwing in some other technology that appears in-game: The original Game Boy!</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/gb.png" />
</p>

<p>The Game Boy is actually mirrored in the final sprite, this was because I wanted to keep a distinctive A and B button visible, but flipping those ended up blending them into the hand somewhat.</p>

<h2 id="random-titlescreen-sprite">Random Titlescreen Sprite</h2>

<p>I could have read the selected player type from the save file and display that on the title screen, but what about cases when creating a new game? I believe the title screen should remain neutral as to the contents of the save file.</p>

<p>Also, the changes I’ve made may already not be to everyone’s tastes so I decided to hold back and default display the boy sprite until the player is at the Continue/New Game menu, from there pressing B will roll RNG and display either the girl or boy sprite.</p>

<p>That relegates the female title screen sprite to somewhat of an easter egg, and I’m okay with that.</p>

<h1 id="other-changes">Other Changes</h1>

<h2 id="script">Script</h2>

<p>There’s still some gendered language in the script, I’ve left that in, but I have made a small alteration in the Game Freak office:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-18.png" />
</p>

<p>Yes technically the artist didn’t draw this character, and I’m not going to insert myself into the Game Freak offices of the game - so I switched the dialogue to a nod to the history of the “lost female trainer”.</p>

<hr />

<p>There’s a secret that I ported from shinpokered, but I won’t spoil that!</p>

<h2 id="gameplay">Gameplay</h2>

<p>The shinpokered lite improvements are all here, so smarter trainer AI, fixed bugs, etc.</p>

<h3 id="one-quality-of-life-feature">One quality of life feature…</h3>

<p>I ported one thing that frustrated me about the original games:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-19.png" />
</p>

<p>This screenshot might not look special to players used to games after the first generation, but at the upper left is a caught Pokémon indicator. That would have been so darn useful for my complete Pokédex runs!</p>

<h3 id="starter-pokémon">Starter Pokémon</h3>

<p>This change I think will be most controversial. To allow the player to mimic the manga scenario, as well as to introduce some variety, when playing as the girl trainer the rival will pick the Pokémon that is <strong>weak</strong> to your choice.</p>

<p align="center">
    <video controls="" width="100%">
        <source src="https://felixjones.co.uk/assets/pokegreen/battle.webm" type="video/webm" />
    </video>
</p>

<p>This makes the girl trainer a sort of “easy” option, something that I’m okay with as generally the rival battles aren’t much of a problem. I also think this is the type of strange decision that is characteristic of the weirdness of the first generation of Pokémon.</p>

<h3 id="default-names">Default names</h3>

<p>Girl trainer ROM hacks always change the default names, shinpokered no exception (opting VIOLET, CLAIRE, and JILL).</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/bgb00026.png" />
</p>

<p>GREEN, LEAF, and CRYSTAL are also common choices, but I wanted default names that felt more in the spirit of the original default names for the Japanese releases of Red, Green, and Blue:</p>

<ul>
  <li>RED/GREEN/BLUE (the edition of the game)</li>
  <li>SATOSHI/SHIGERU/TSUNEKAZ</li>
  <li>JACK/JOHN/JEAN</li>
</ul>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-9.png" />
</p>

<p>BLUE makes sense to keep, as that is the name of the manga character in Japan (localised to Green in the west, as Blue was used for the rival).</p>

<p>SATOSHI/SHIGERU/TSUNEKAZ are quite male Japaneese names, so for that reason I opted to select a name of a woman known to work at Game Freak during Red and Green’s development: <a href="https://en.wikipedia.org/wiki/Atsuko_Nishida">Atsuko Nishida</a>.</p>

<p>Luckily JEAN is a gender neutral name, so keeping that choice made most sense.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/pokegreen/pokegreen-20.png" />
</p>

<p>I can see where other ROM hacks decided to use the name JILL as the rhyme of Jack &amp; Jill provides a female counter part name to the default of “JACK”. But I am happy with JEAN.</p>

<h1 id="rom-hack-release">ROM Hack Release</h1>

<p>I am currently testing the ROM hack before I release an IPS patch for it. I will also open source my changes as a branch of shinpokered.</p>

<p><a href="https://retrodev.social/@xilefian">Follow me on the Fediverse</a> or <a href="https://bsky.app/profile/xilefian.retrodev.social">Bluesky</a> to get notified of the release.</p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[Wild SIDE'HACK appeared!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://felixjones.co.uk/assets/pokegreen/side_hack.png" /><media:content medium="image" url="https://felixjones.co.uk/assets/pokegreen/side_hack.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Serialising Binary in C++23</title><link href="https://felixjones.co.uk/2025/03/01/serialisation.html" rel="alternate" type="text/html" title="Serialising Binary in C++23" /><published>2025-03-01T00:00:00+00:00</published><updated>2025-03-01T00:00:00+00:00</updated><id>https://felixjones.co.uk/2025/03/01/serialisation</id><content type="html" xml:base="https://felixjones.co.uk/2025/03/01/serialisation.html"><![CDATA[<p>This is the first post in a series that documents the interesting things I encounter as I develop a Game Boy Advance game in 2025 (not yet announced).</p>

<hr />

<p>I am British, so whilst my technical write-up will spell “serial<em>ize</em>” the British way (serial<em>ise</em>) any code samples will be in American English (ie: <code class="language-plaintext highlighter-rouge">serializer::deserialize</code>).</p>

<h1 id="serialising-binary-in-c23">Serialising Binary in C++23</h1>

<p>I do not consider serialisation a difficult task, indeed there’s the naïve tried-and-true technique of manually writing a binary writer and a binary reader for each type:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">my_type</span> <span class="p">{</span>
    <span class="k">auto</span> <span class="n">serialize</span><span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">archive</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="n">archive</span><span class="p">.</span><span class="n">write_integer</span><span class="p">(</span><span class="n">m_foo</span><span class="p">);</span>
        <span class="n">archive</span><span class="p">.</span><span class="n">write_string</span><span class="p">(</span><span class="n">m_bar</span><span class="p">);</span>
    <span class="p">}</span>
    
    <span class="k">auto</span> <span class="n">deserialize</span><span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">archive</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="n">m_foo</span> <span class="o">=</span> <span class="n">archive</span><span class="p">.</span><span class="n">read_integer</span><span class="p">();</span>
        <span class="n">m_bar</span> <span class="o">=</span> <span class="n">archive</span><span class="p">.</span><span class="n">read_string</span><span class="p">();</span>
    <span class="p">}</span>
<span class="nl">private:</span>
    <span class="kt">int</span> <span class="n">m_foo</span><span class="p">{</span><span class="mi">42</span><span class="p">};</span>
    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">m_bar</span><span class="p">{</span><span class="s">"Hello"</span><span class="p">};</span>
<span class="p">};</span>
</code></pre></div></div>

<p>But at work I have recently been writing some code for Minecraft Java Edition, and a feature in that codebase that I’ve always enjoyed is the codecs in the <a href="https://github.com/Mojang/DataFixerUpper">DataFixerUpper library</a>, specifically <a href="https://github.com/Mojang/DataFixerUpper/blob/d0f713b0719b5f1ad77506e6a019c41782b8bcf1/src/test/java/com/mojang/serialization/RoundtripTest.java#L73-L101">see the syntax for serialising the <code class="language-plaintext highlighter-rouge">TestData</code> record</a>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">private</span> <span class="n">record</span> <span class="nf">TestData</span><span class="o">(</span>
    <span class="kt">float</span> <span class="n">a</span><span class="o">,</span>
    <span class="kt">double</span> <span class="n">b</span><span class="o">,</span>
    <span class="kt">byte</span> <span class="n">c</span><span class="o">,</span>
    <span class="kt">short</span> <span class="n">d</span><span class="o">,</span>
    <span class="kt">int</span> <span class="n">e</span><span class="o">,</span>
    <span class="kt">long</span> <span class="n">f</span><span class="o">,</span>
    <span class="kt">boolean</span> <span class="n">g</span><span class="o">,</span>
    <span class="nc">String</span> <span class="n">h</span><span class="o">,</span>
    <span class="nc">List</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">i</span><span class="o">,</span>
    <span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;</span> <span class="n">j</span><span class="o">,</span>
    <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;&gt;</span> <span class="n">k</span><span class="o">,</span>
    <span class="nc">DayData</span> <span class="n">dayData</span>
<span class="o">)</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Codec</span><span class="o">&lt;</span><span class="nc">TestData</span><span class="o">&gt;</span> <span class="no">CODEC</span> <span class="o">=</span> <span class="nc">RecordCodecBuilder</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">i</span> <span class="o">-&gt;</span> <span class="n">i</span><span class="o">.</span><span class="na">group</span><span class="o">(</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">FLOAT</span><span class="o">.</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"a"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">a</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">DOUBLE</span><span class="o">.</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"b"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">b</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">BYTE</span><span class="o">.</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"c"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">c</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">SHORT</span><span class="o">.</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"d"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">d</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">INT</span><span class="o">.</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"e"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">e</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">LONG</span><span class="o">.</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"f"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">f</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">BOOL</span><span class="o">.</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"g"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">g</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">STRING</span><span class="o">.</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"h"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">h</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">STRING</span><span class="o">.</span><span class="na">listOf</span><span class="o">().</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"i"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">i</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">unboundedMap</span><span class="o">(</span><span class="nc">Codec</span><span class="o">.</span><span class="na">STRING</span><span class="o">,</span> <span class="nc">Codec</span><span class="o">.</span><span class="na">STRING</span><span class="o">).</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"j"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">j</span><span class="o">),</span>
        <span class="nc">Codec</span><span class="o">.</span><span class="na">compoundList</span><span class="o">(</span><span class="nc">Codec</span><span class="o">.</span><span class="na">STRING</span><span class="o">,</span> <span class="nc">Codec</span><span class="o">.</span><span class="na">STRING</span><span class="o">).</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"k"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">k</span><span class="o">),</span>
        <span class="nc">DayData</span><span class="o">.</span><span class="na">CODEC</span><span class="o">.</span><span class="na">fieldOf</span><span class="o">(</span><span class="s">"day_data"</span><span class="o">).</span><span class="na">forGetter</span><span class="o">(</span><span class="n">d</span> <span class="o">-&gt;</span> <span class="n">d</span><span class="o">.</span><span class="na">dayData</span><span class="o">)</span>
    <span class="o">).</span><span class="na">apply</span><span class="o">(</span><span class="n">i</span><span class="o">,</span> <span class="nl">TestData:</span><span class="o">:</span><span class="k">new</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>

<p>That <code class="language-plaintext highlighter-rouge">CODEC</code> static field is our serialiser, notice that there’s no separate “serialize” and “deserialize” methods, just a definition of what fields there are, what the getters are, what constructor takes these arguments.</p>

<p>I really enjoy writing these <code class="language-plaintext highlighter-rouge">Codec</code> implementations, and the programmer zen of writing DFU Codecs is something I miss when I’m working on Bedrock in C++20.</p>

<hr />

<p>Serialisation is needed for my Game Boy Advance side-project, and this gave me an opportunity to try implementing something closer to DFU’s Codecs than what we traditionally see in the C++ serialiser landscape.</p>

<p>I don’t need most of the features of DFU, I only need to write binary data and I don’t even have to worry about versioning data for game updates considering this is a GBA project.</p>

<h1 id="all-in-on-constexpr">All in on Constexpr</h1>

<p>I’ve been using <code class="language-plaintext highlighter-rouge">constexpr</code> a lot for the GBA, and I consider it the primary thing that makes C++ a sensible choice for the GBA.</p>

<p>For a serialiser I believe <code class="language-plaintext highlighter-rouge">constexpr</code> is very important as we can give the compiler all the information about our types and it should, in theory, be able to optimise down to just calling the binary functions for encoding/decoding our types.</p>

<p>See what the above Java Codec looks like in my C++ interpretation:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">test_data</span> <span class="p">{</span>
    <span class="kt">float</span> <span class="n">a</span><span class="p">;</span>
    <span class="kt">double</span> <span class="n">b</span><span class="p">;</span>
    <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">c</span><span class="p">;</span>
    <span class="kt">short</span> <span class="n">d</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">e</span><span class="p">;</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">f</span><span class="p">;</span>
    <span class="kt">bool</span> <span class="n">g</span><span class="p">;</span>

    <span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">codec</span> <span class="o">=</span> <span class="n">tuple_codec</span><span class="p">(</span>
       <span class="n">float_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">test_data</span><span class="o">::</span><span class="n">a</span><span class="p">),</span>
       <span class="n">double_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">test_data</span><span class="o">::</span><span class="n">b</span><span class="p">),</span>
       <span class="n">unsigned_char_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">test_data</span><span class="o">::</span><span class="n">c</span><span class="p">),</span>
       <span class="n">short_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">test_data</span><span class="o">::</span><span class="n">d</span><span class="p">),</span>
       <span class="n">int_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">test_data</span><span class="o">::</span><span class="n">e</span><span class="p">),</span>
       <span class="n">long_long_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">test_data</span><span class="o">::</span><span class="n">f</span><span class="p">),</span>
       <span class="n">bool_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">test_data</span><span class="o">::</span><span class="n">g</span><span class="p">)</span>
   <span class="p">).</span><span class="n">apply</span><span class="o">&lt;</span><span class="n">test_data</span><span class="o">&gt;</span><span class="p">();</span>
<span class="p">};</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">test_data::codec</code> static member is entirely built at compile-time, so the order of binary encoding/decoding functions to call for this type should be known to the compiler, letting it in theory optimise this all the way down to just the reading and writing of raw bytes.</p>

<hr />

<p>In my current implementation I can see this:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">foo</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">b</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">c</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">d</span><span class="p">;</span>

    <span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">codec</span> <span class="o">=</span> <span class="n">tuple_codec</span><span class="p">(</span>
       <span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">foo</span><span class="o">::</span><span class="n">a</span><span class="p">),</span>
       <span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">foo</span><span class="o">::</span><span class="n">b</span><span class="p">),</span>
       <span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">foo</span><span class="o">::</span><span class="n">c</span><span class="p">),</span>
       <span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">foo</span><span class="o">::</span><span class="n">d</span><span class="p">)</span>
   <span class="p">).</span><span class="n">apply</span><span class="o">&lt;</span><span class="n">foo</span><span class="o">&gt;</span><span class="p">();</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">serialized</span> <span class="o">=</span> <span class="n">foo</span><span class="o">::</span><span class="n">codec</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="n">foo</span><span class="p">{</span>
        <span class="p">.</span><span class="n">a</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>
        <span class="p">.</span><span class="n">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>
        <span class="p">.</span><span class="n">c</span> <span class="o">=</span> <span class="mi">3</span><span class="p">,</span>
        <span class="p">.</span><span class="n">d</span> <span class="o">=</span> <span class="mi">4</span>
    <span class="p">});</span>
    <span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>

<pre><code class="language-arm">movs r3, #1           
movs r0, r5                            
add r1, sp, #24                    
str r3, [sp, #24]               
bl 0x8000780 &lt;util::append_insert_iterator&lt;std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; &gt;::operator=&lt;std::array&lt;char, 4u&gt; &gt;(std::array&lt;char, 4u&gt;&amp;&amp;)&gt;
movs r3, #2                     
movs r0, r5                     
add r1, sp, #20                
str r3, [sp, #20]               
bl 0x8000780 &lt;util::append_insert_iterator&lt;std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; &gt;::operator=&lt;std::array&lt;char, 4u&gt; &gt;(std::array&lt;char, 4u&gt;&amp;&amp;)&gt;
movs r3, #3                     
movs r0, r5                     
add r1, sp, #16                 
str r3, [sp, #16]               
bl 0x8000780 &lt;util::append_insert_iterator&lt;std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; &gt;::operator=&lt;std::array&lt;char, 4u&gt; &gt;(std::array&lt;char, 4u&gt;&amp;&amp;)&gt;
movs r3, #4                     
movs r0, r5                     
add r1, sp, #12                 
str r3, [sp, #12]               
bl 0x8000780 &lt;util::append_insert_iterator&lt;std::__cxx11::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; &gt;::operator=&lt;std::array&lt;char, 4u&gt; &gt;(std::array&lt;char, 4u&gt;&amp;&amp;)&gt;
</code></pre>

<p>Those four integer encodes are compiled into directly appending four <code class="language-plaintext highlighter-rouge">std::array&lt;char, 4u&gt;</code> chunks onto the end of a string.</p>

<p>I think this is remarkable, we’re able to remove all the cost of the serialisation library down to just reading and writing bytes.</p>

<h1 id="binary-serialiseto-a-string">Binary serialise…To a String?</h1>

<p>In my little snippet above you’ll notice that I serialised to a string:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">serialized</span> <span class="o">=</span> <span class="n">foo</span><span class="o">::</span><span class="n">codec</span><span class="p">.</span><span class="n">encode</span><span class="p">(</span><span class="n">foo</span><span class="p">{</span> <span class="p">...</span> <span class="p">});</span>
</code></pre></div></div>

<p>There’s a feature that <code class="language-plaintext highlighter-rouge">std::string</code> has that <code class="language-plaintext highlighter-rouge">std::vector</code> does not: <em>Small String Optimisation</em>.</p>

<p><a href="https://devblogs.microsoft.com/oldnewthing/20230803-00/?p=108532">Here’s a link to Raymond Chen’s article on the guts of <code class="language-plaintext highlighter-rouge">std::string</code> that covers this optimisation</a>, but the short of it is that if the data in a string is “small” then it won’t bother with a heap allocation and will actually store the data within the string itself (which is probably on the stack).</p>

<p>Boost has <a href="https://live.boost.org/doc/libs/1_85_0/doc/html/boost/container/small_vector.html">small_vector</a> which implements this for vector, but I’m not using Boost and I only need to serialise bytes, and when <code class="language-plaintext highlighter-rouge">sizeof(char) == 1</code> I might aswell use <code class="language-plaintext highlighter-rouge">std::string</code> instead of <code class="language-plaintext highlighter-rouge">std::vector&lt;char&gt;</code>.</p>

<p>Fundamental types will serialise to something within a small string, so this optimisation pays off for the GBA where heap allocations occur on the slow 256 KiB RAM.</p>

<h1 id="encoding--decoding-fundamental-types">Encoding &amp; Decoding Fundamental Types</h1>

<p>The DataFixerUpper library has a set of primitive types that it has encoding operations for: defined in <a href="https://github.com/Mojang/DataFixerUpper/blob/master/src/main/java/com/mojang/serialization/DynamicOps.java#L22">DynamicOps.java</a>.</p>

<p>For C++ these would be our <a href="https://en.cppreference.com/w/cpp/language/types">fundamental types</a>.</p>

<p>Because our fundamental types are <code class="language-plaintext highlighter-rouge">constexpr</code> themselves, we can implement their encode/decode with <code class="language-plaintext highlighter-rouge">std::bit_cast</code> to and from an array of bytes:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">copy_encoder</span> <span class="p">{</span>
    <span class="k">template</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">convertible_to</span><span class="o">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">O</span><span class="p">,</span> <span class="n">AppendInserter</span> <span class="n">Out</span><span class="o">&gt;</span>
    <span class="k">static</span> <span class="k">constexpr</span> <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="n">O</span><span class="o">&amp;&amp;</span> <span class="n">obj</span><span class="p">,</span> <span class="n">Out</span><span class="o">&amp;&amp;</span> <span class="n">out</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">out</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">bit_cast</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">T</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">O</span><span class="o">&gt;</span><span class="p">(</span><span class="n">obj</span><span class="p">));</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">copy_decoder</span> <span class="p">{</span>
    <span class="k">template</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">input_iterator</span> <span class="n">In</span><span class="p">&gt;</span>
    <span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="k">operator</span><span class="p">()(</span><span class="n">In</span><span class="o">&amp;&amp;</span> <span class="n">in</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">array</span><span class="o">&lt;</span><span class="kt">char</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">T</span><span class="p">)</span><span class="o">&gt;</span> <span class="n">data</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="k">auto</span><span class="o">&amp;</span> <span class="n">c</span> <span class="o">:</span> <span class="n">data</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">c</span> <span class="o">=</span> <span class="o">*</span><span class="n">in</span><span class="o">++</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">bit_cast</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">data</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Actually these copy encoders are good for anything that is <code class="language-plaintext highlighter-rouge">std::bit_cast</code> compatible (which is anything that is <code class="language-plaintext highlighter-rouge">std::is_trivially_copyable_v</code>), so the fundamental types can all use a <code class="language-plaintext highlighter-rouge">trivially_copyable_codec</code>:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span> <span class="k">requires</span> <span class="n">std</span><span class="o">::</span><span class="n">is_trivially_copyable_v</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="k">constexpr</span> <span class="k">auto</span> <span class="nf">trivially_copyable_codec</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">codec</span><span class="p">(</span><span class="n">copy_encoder</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">{},</span> <span class="n">copy_decoder</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">{});</span>
<span class="p">}</span>

<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">int_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">unsigned_int_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">short_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">short</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">unsigned_short_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">short</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">long_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">long</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">unsigned_long_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">long</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">long_long_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">long</span> <span class="kt">long</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">unsigned_long_long_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">long</span> <span class="kt">long</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">float_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">float</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">double_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">long_double_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">long</span> <span class="kt">double</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">char_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">signed_char_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">signed</span> <span class="kt">char</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">unsigned_char_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">wchar_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">wchar_t</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">char8_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="k">char8_t</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">char16_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">char16_t</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">char32_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">char32_t</span><span class="o">&gt;</span><span class="p">();</span>
<span class="kr">inline</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">bool_codec</span> <span class="o">=</span> <span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span><span class="p">();</span>
</code></pre></div></div>

<p>If we have a type that is trivial then we have the option of a simple byte copy codec:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">my_type</span> <span class="p">{</span>
    <span class="k">static</span> <span class="k">consteval</span> <span class="k">auto</span> <span class="n">codec</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="n">util</span><span class="o">::</span><span class="n">trivially_copyable_codec</span><span class="o">&lt;</span><span class="n">my_type</span><span class="o">&gt;</span><span class="p">();</span> <span class="p">}</span>

    <span class="kt">int</span> <span class="n">a</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">b</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<h2 id="the-arguably-fundamental-types">The Arguably Fundamental Types</h2>

<p>I’ll never argue that <code class="language-plaintext highlighter-rouge">std::tuple</code> is a C++23 fundamental type, but things being tuple-like is quite fundamental in writing C++. Structs and Classes can be argued as being fancy tuples, so to support serialising these I have a generic <code class="language-plaintext highlighter-rouge">tuple_codec</code>.</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span><span class="o">...</span> <span class="nc">Codecs</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">tuple_encoder</span> <span class="p">{</span>
    <span class="k">constexpr</span> <span class="k">explicit</span> <span class="n">tuple_encoder</span><span class="p">(</span><span class="n">Codecs</span><span class="p">...</span> <span class="n">codecs</span><span class="p">)</span> <span class="o">:</span> <span class="n">m_encoder</span><span class="p">{</span> <span class="n">codecs</span><span class="p">.</span><span class="n">encoder</span><span class="p">()...</span> <span class="p">}</span> <span class="p">{}</span>

    <span class="k">template</span><span class="o">&lt;</span><span class="n">has_std_get</span> <span class="n">T</span><span class="p">,</span> <span class="n">AppendInserter</span> <span class="n">Out</span><span class="p">&gt;</span>
    <span class="k">constexpr</span> <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="n">T</span><span class="o">&amp;&amp;</span> <span class="n">obj</span><span class="p">,</span> <span class="n">Out</span><span class="o">&amp;&amp;</span> <span class="n">out</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="p">[</span><span class="o">&amp;</span><span class="p">]</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="p">...</span> <span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">index_sequence</span><span class="o">&lt;</span><span class="n">I</span><span class="p">...</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">constexpr</span> <span class="p">{</span>
            <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="n">m_encoder</span><span class="p">),</span> <span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">obj</span><span class="p">)),</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Out</span><span class="o">&gt;</span><span class="p">(</span><span class="n">out</span><span class="p">)),</span> <span class="p">...);</span>
        <span class="p">}(</span><span class="n">std</span><span class="o">::</span><span class="n">make_index_sequence</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">tuple_size_v</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">m_encoder</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="p">{});</span>
    <span class="p">}</span>

    <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">,</span> <span class="n">AppendInserter</span> <span class="n">Out</span><span class="p">&gt;</span>
    <span class="k">constexpr</span> <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="n">T</span><span class="o">&amp;&amp;</span> <span class="n">obj</span><span class="p">,</span> <span class="n">Out</span><span class="o">&amp;&amp;</span> <span class="n">out</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="p">[</span><span class="o">&amp;</span><span class="p">]</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="p">...</span> <span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">index_sequence</span><span class="o">&lt;</span><span class="n">I</span><span class="p">...</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">constexpr</span> <span class="p">{</span>
            <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="n">m_encoder</span><span class="p">),</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">obj</span><span class="p">),</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Out</span><span class="o">&gt;</span><span class="p">(</span><span class="n">out</span><span class="p">)),</span> <span class="p">...);</span>
        <span class="p">}(</span><span class="n">std</span><span class="o">::</span><span class="n">make_index_sequence</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">tuple_size_v</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">m_encoder</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="p">{});</span>
    <span class="p">}</span>
<span class="nl">protected:</span>
    <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="o">&lt;</span><span class="n">encoder_type</span><span class="o">&lt;</span><span class="n">Codecs</span><span class="o">&gt;</span><span class="p">...</span><span class="o">&gt;</span> <span class="n">m_encoder</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Notice how the tuple encoder has an overload for using <code class="language-plaintext highlighter-rouge">std::get&lt;&gt;</code> versus forwarding the object reference to all of the tuple element encoders.</p>

<p>The latter overload is the mechanism that handles serialising member variables (the former is the true serialiser for tuple-like).</p>

<p>But what’s the point of forwarding the same object to all the encoders? If the encoders were aware of the incoming object type, and also knew of a member function or member variabel of that object, then it can choose to encode that specific member of the object and nothing else. This is what the <code class="language-plaintext highlighter-rouge">codec&lt;&gt;::of_member</code> function is for.</p>

<hr />

<p>The tuple decoder calls <code class="language-plaintext highlighter-rouge">std::make_tuple</code> using the results of the tuple element decoders.</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span><span class="o">...</span> <span class="nc">Codecs</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">tuple_decoder</span> <span class="p">{</span>
    <span class="k">explicit</span> <span class="k">constexpr</span> <span class="n">tuple_decoder</span><span class="p">(</span><span class="n">Codecs</span><span class="p">...</span> <span class="n">codecs</span><span class="p">)</span> <span class="o">:</span> <span class="n">m_decoder</span><span class="p">{</span> <span class="n">codecs</span><span class="p">.</span><span class="n">decoder</span><span class="p">()...</span> <span class="p">}</span> <span class="p">{}</span>

    <span class="k">template</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">input_iterator</span> <span class="n">In</span><span class="p">&gt;</span>
    <span class="k">constexpr</span> <span class="k">auto</span> <span class="k">operator</span><span class="p">()(</span><span class="n">In</span><span class="o">&amp;&amp;</span> <span class="n">in</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="k">return</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">]</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="p">...</span> <span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">index_sequence</span><span class="o">&lt;</span><span class="n">I</span><span class="p">...</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">constexpr</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">make_tuple</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="n">m_decoder</span><span class="p">),</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">In</span><span class="o">&gt;</span><span class="p">(</span><span class="n">in</span><span class="p">))...);</span>
        <span class="p">}(</span><span class="n">std</span><span class="o">::</span><span class="n">make_index_sequence</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">tuple_size_v</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">m_decoder</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="p">{});</span>
    <span class="p">}</span>
<span class="nl">protected:</span>
    <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="o">&lt;</span><span class="n">decoder_type</span><span class="o">&lt;</span><span class="n">Codecs</span><span class="o">&gt;</span><span class="p">...</span><span class="o">&gt;</span> <span class="n">m_decoder</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>This certainly works for tuple-like, but what about our objects with serialised member variables?</p>

<p>That’s where the <code class="language-plaintext highlighter-rouge">apply</code> comes into it, which adds decoders specific for member variables:</p>

<h3 id="applying-lambdas">Applying lambdas</h3>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">Decoder</span><span class="p">,</span> <span class="k">typename</span> <span class="nc">Ctor</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">apply_lambda</span> <span class="p">{</span>
    <span class="k">constexpr</span> <span class="n">apply_lambda</span><span class="p">(</span><span class="n">Decoder</span> <span class="n">decoder</span><span class="p">,</span> <span class="n">Ctor</span> <span class="n">constructor</span><span class="p">)</span> <span class="o">:</span> <span class="n">m_decoder</span><span class="p">{</span> <span class="n">decoder</span> <span class="p">},</span> <span class="n">m_constructor</span><span class="p">{</span> <span class="n">constructor</span> <span class="p">}</span> <span class="p">{}</span>

    <span class="k">template</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">input_iterator</span> <span class="n">In</span><span class="p">&gt;</span>
    <span class="k">constexpr</span> <span class="k">auto</span> <span class="k">operator</span><span class="p">()(</span><span class="n">In</span><span class="o">&amp;&amp;</span> <span class="n">in</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="k">if</span> <span class="k">constexpr</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="n">result</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">m_decoder</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">In</span><span class="o">&gt;</span><span class="p">(</span><span class="n">in</span><span class="p">));</span> <span class="n">std</span><span class="o">::</span><span class="n">invocable</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">m_constructor</span><span class="p">),</span> <span class="k">decltype</span><span class="p">(</span><span class="n">result</span><span class="p">)</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">m_constructor</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span> <span class="c1">// For the case where we actually want a tuple as an argument</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">apply</span><span class="p">(</span><span class="n">m_constructor</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span> <span class="c1">// For the case where we want to forward each tuple argument</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="nl">protected:</span>
    <span class="n">Decoder</span> <span class="n">m_decoder</span><span class="p">;</span>
    <span class="n">Ctor</span> <span class="n">m_constructor</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">apply_lambda</code> forwards the <code class="language-plaintext highlighter-rouge">std::make_tuple</code> result into the parameters of a given lambda, allowing for something like:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">foo</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">bar</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">baz</span><span class="p">;</span>

    <span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">codec</span> <span class="o">=</span> <span class="n">tuple_codec</span><span class="p">(</span>
        <span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">foo</span><span class="o">::</span><span class="n">bar</span><span class="p">),</span>
        <span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">foo</span><span class="o">::</span><span class="n">baz</span><span class="p">)</span>
    <span class="p">).</span><span class="n">apply</span><span class="p">([](</span><span class="kt">int</span> <span class="n">bar</span><span class="p">,</span> <span class="kt">int</span> <span class="n">baz</span><span class="p">)</span> <span class="k">constexpr</span> <span class="p">{</span>
        <span class="c1">// We could assert that our parameters are within constraints here</span>
        <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">make_unique</span><span class="o">&lt;</span><span class="n">foo</span><span class="o">&gt;</span><span class="p">(</span><span class="n">bar</span><span class="p">,</span> <span class="n">baz</span><span class="p">);</span> <span class="c1">// Always deserialises to a unique_ptr</span>
    <span class="p">});</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="applying-tuples">Applying tuples</h3>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">Decoder</span><span class="p">,</span> <span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">apply_tuple</span> <span class="p">{</span>
    <span class="k">constexpr</span> <span class="k">explicit</span> <span class="n">apply_tuple</span><span class="p">(</span><span class="n">Decoder</span> <span class="n">decoder</span><span class="p">)</span> <span class="o">:</span> <span class="n">m_decoder</span><span class="p">{</span> <span class="n">decoder</span> <span class="p">}</span> <span class="p">{}</span>

    <span class="k">template</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">input_iterator</span> <span class="n">In</span><span class="p">&gt;</span>
    <span class="k">constexpr</span> <span class="k">auto</span> <span class="k">operator</span><span class="p">()(</span><span class="n">In</span><span class="o">&amp;&amp;</span> <span class="n">in</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">make_from_tuple</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">m_decoder</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">In</span><span class="o">&gt;</span><span class="p">(</span><span class="n">in</span><span class="p">)));</span>
    <span class="p">}</span>
<span class="nl">protected:</span>
    <span class="n">Decoder</span> <span class="n">m_decoder</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">apply_tuple</code> forwards the result of <code class="language-plaintext highlighter-rouge">std::make_tuple</code> to <a href="https://en.cppreference.com/w/cpp/utility/make_from_tuple"><code class="language-plaintext highlighter-rouge">std::make_from_tuple</code></a>, which will call whatever constructor for type <code class="language-plaintext highlighter-rouge">T</code> matches the given tuple arguments.</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">foo</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">bar</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">baz</span><span class="p">;</span>

    <span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">codec</span> <span class="o">=</span> <span class="n">tuple_codec</span><span class="p">(</span>
        <span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">foo</span><span class="o">::</span><span class="n">bar</span><span class="p">),</span>
        <span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">.</span><span class="n">of_member</span><span class="p">(</span><span class="o">&amp;</span><span class="n">foo</span><span class="o">::</span><span class="n">baz</span><span class="p">)</span>
    <span class="p">).</span><span class="n">apply</span><span class="o">&lt;</span><span class="n">foo</span><span class="o">&gt;</span><span class="p">();</span> <span class="c1">// Fowards to apply_tuple</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="applying-ranges">Applying ranges</h3>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">Decoder</span><span class="p">,</span> <span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">apply_range</span> <span class="p">{</span>
    <span class="k">constexpr</span> <span class="k">explicit</span> <span class="n">apply_range</span><span class="p">(</span><span class="n">Decoder</span> <span class="n">decoder</span><span class="p">)</span> <span class="o">:</span> <span class="n">m_decoder</span><span class="p">{</span> <span class="n">decoder</span> <span class="p">}</span> <span class="p">{}</span>

    <span class="k">template</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">input_iterator</span> <span class="n">In</span><span class="p">&gt;</span>
    <span class="k">constexpr</span> <span class="k">auto</span> <span class="k">operator</span><span class="p">()(</span><span class="n">In</span><span class="o">&amp;&amp;</span> <span class="n">in</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">m_decoder</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">In</span><span class="o">&gt;</span><span class="p">(</span><span class="n">in</span><span class="p">)));</span>
    <span class="p">}</span>
<span class="nl">protected:</span>
    <span class="n">Decoder</span> <span class="n">m_decoder</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Applying ranges only makes sense if we can support encoding ranges:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">Codec</span><span class="p">,</span> <span class="k">typename</span> <span class="nc">IndexCodec</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">range_encoder</span> <span class="p">{</span>
    <span class="k">constexpr</span> <span class="n">range_encoder</span><span class="p">(</span><span class="n">Codec</span> <span class="n">codec</span><span class="p">,</span> <span class="n">IndexCodec</span> <span class="n">indexCodec</span><span class="p">)</span> <span class="o">:</span> <span class="n">m_encoder</span><span class="p">{</span> <span class="n">codec</span><span class="p">.</span><span class="n">encoder</span><span class="p">()</span> <span class="p">},</span> <span class="n">m_indexEncoder</span><span class="p">{</span> <span class="n">indexCodec</span><span class="p">.</span><span class="n">encoder</span><span class="p">()</span> <span class="p">}</span> <span class="p">{}</span>

    <span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">,</span> <span class="n">AppendInserter</span> <span class="n">Out</span><span class="p">&gt;</span> <span class="k">requires</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">range</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
    <span class="k">constexpr</span> <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="n">T</span><span class="o">&amp;&amp;</span> <span class="n">range</span><span class="p">,</span> <span class="n">Out</span><span class="o">&amp;&amp;</span> <span class="n">out</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">m_indexEncoder</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">size</span><span class="p">(</span><span class="n">range</span><span class="p">),</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Out</span><span class="o">&gt;</span><span class="p">(</span><span class="n">out</span><span class="p">));</span>
        <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">for_each</span><span class="p">(</span><span class="n">range</span><span class="p">,</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">]</span><span class="o">&lt;</span><span class="k">typename</span> <span class="n">O</span><span class="o">&gt;</span><span class="p">(</span><span class="n">O</span><span class="o">&amp;&amp;</span> <span class="n">obj</span><span class="p">)</span> <span class="k">constexpr</span> <span class="p">{</span>
            <span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">m_encoder</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">O</span><span class="o">&gt;</span><span class="p">(</span><span class="n">obj</span><span class="p">),</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Out</span><span class="o">&gt;</span><span class="p">(</span><span class="n">out</span><span class="p">));</span>
        <span class="p">});</span>
    <span class="p">}</span>
<span class="nl">protected:</span>
    <span class="n">encoder_type</span><span class="o">&lt;</span><span class="n">Codec</span><span class="o">&gt;</span> <span class="n">m_encoder</span><span class="p">;</span>
    <span class="n">encoder_type</span><span class="o">&lt;</span><span class="n">IndexCodec</span><span class="o">&gt;</span> <span class="n">m_indexEncoder</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>We can now serialise some standard containers:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">vector_of_int_codec</span> <span class="o">=</span> <span class="n">range_codec</span><span class="p">(</span><span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">).</span><span class="n">apply</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span><span class="p">();</span>
<span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">list_of_int_codec</span> <span class="o">=</span> <span class="n">range_codec</span><span class="p">(</span><span class="n">util</span><span class="o">::</span><span class="n">int_codec</span><span class="p">).</span><span class="n">apply</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span><span class="p">();</span>
<span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">string_codec</span> <span class="o">=</span> <span class="n">range_codec</span><span class="p">(</span><span class="n">util</span><span class="o">::</span><span class="n">char_codec</span><span class="p">).</span><span class="n">apply</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span><span class="p">();</span>
<span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">key_value_codec</span> <span class="o">=</span> <span class="n">range_codec</span><span class="p">(</span><span class="n">tuple_codec</span><span class="p">(</span><span class="n">string_codec</span><span class="p">,</span> <span class="n">string_codec</span><span class="p">));</span>
</code></pre></div></div>

<h3 id="applying-ranges-of-tuples">Applying ranges of tuples</h3>

<p>The final step to this would be supporting <code class="language-plaintext highlighter-rouge">std::map</code>-like containers, which requires applying a range of tuples.</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">Decoder</span><span class="p">,</span> <span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">apply_range_of_tuple</span> <span class="p">{</span>
    <span class="k">constexpr</span> <span class="k">explicit</span> <span class="n">apply_range_of_tuple</span><span class="p">(</span><span class="n">Decoder</span> <span class="n">decoder</span><span class="p">)</span> <span class="o">:</span> <span class="n">m_decoder</span><span class="p">{</span> <span class="n">decoder</span> <span class="p">}</span> <span class="p">{}</span>

    <span class="k">template</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">input_iterator</span> <span class="n">In</span><span class="p">&gt;</span>
    <span class="k">constexpr</span> <span class="k">auto</span> <span class="k">operator</span><span class="p">()(</span><span class="n">In</span><span class="o">&amp;&amp;</span> <span class="n">in</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">ranges</span><span class="o">::</span><span class="n">to</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">invoke</span><span class="p">(</span><span class="n">m_decoder</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">In</span><span class="o">&gt;</span><span class="p">(</span><span class="n">in</span><span class="p">)));</span>
    <span class="p">}</span>
<span class="nl">protected:</span>
    <span class="n">Decoder</span> <span class="n">m_decoder</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>This applies to constructors such as <code class="language-plaintext highlighter-rouge">std::unordered_map</code>:</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="k">constexpr</span> <span class="k">auto</span> <span class="n">map_codec</span> <span class="o">=</span> <span class="n">range_codec</span><span class="p">(</span>
    <span class="n">tuple_codec</span><span class="p">(</span><span class="n">int_codec</span><span class="p">,</span> <span class="n">int_codec</span><span class="p">)</span>
<span class="p">).</span><span class="n">apply</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">unordered_map</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;&gt;</span><span class="p">();</span>
</code></pre></div></div>

<p>It was a very cool moment when writing the above worked first time, as I was expecting to be writing specialisations for <code class="language-plaintext highlighter-rouge">std::map</code>-like support.</p>

<h1 id="now-my-compile-times-are-long">Now my compile times are long</h1>

<p>These codecs add a good second or so to my compile time, and that could be unacceptable for larger projects.</p>

<h2 id="and-the-error-messages-are-even-longer">And the error messages are even longer</h2>

<p>There is some very deeply nested templates at work here, so when a compile error does happen the resulting message is just impossible for a human to decipher. This has probably slowed down development of my binary serialiser the most.</p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[This is the first post in a series that documents the interesting things I encounter as I develop a Game Boy Advance game in 2025 (not yet announced).]]></summary></entry><entry><title type="html">The Story of the Wearable Barrel</title><link href="https://felixjones.co.uk/2024/01/26/barrels.html" rel="alternate" type="text/html" title="The Story of the Wearable Barrel" /><published>2024-01-26T00:00:00+00:00</published><updated>2024-01-26T00:00:00+00:00</updated><id>https://felixjones.co.uk/2024/01/26/barrels</id><content type="html" xml:base="https://felixjones.co.uk/2024/01/26/barrels.html"><![CDATA[<p>The 2022 April Fools’ update is still my favourite for some Minecraft philosophy reasons, but in particular I snuck my darling Minecraft idea into the joke update.</p>

<hr />

<p>This is my own personal story, and opinions expressed are not representative of Mojang Studios, nor the Minecraft team. Also, some of this story I probably made up and isn’t true.</p>

<h1 id="the-story-of-the-wearable-barrel">The Story of the Wearable Barrel</h1>

<h2 id="the-cave-update">The Cave Update</h2>

<p>This idea actually originated from my first team off-site back in early 2020 during the ideation of what would later become the Caves &amp; Cliffs update.</p>

<p>A chunk of the Vanilla team stayed overnight at some fancy castle to discuss what a “Cave Update” would look like (back then, the community were talking a lot about wanting a “Cave Update”).</p>

<p>By this point, I had already created my Twitter persona of coming up with goofy Minecraft ideas, and I figured that the same process would probably result in some actual ideas related to caves, so I started throwing ideas at the wall to see what would stick.</p>

<h2 id="the-barrel-room">The Barrel Room</h2>

<p>My memory is fuzzy on this one, so some of these details will be made-up for the sake of narrative.</p>

<p>Part of my goofy idea process involves tying the idea vaguely back to a common Minecraft player complaint that I would have seen on Twitter. I remembered one of the complaints being the Wandering Trader appearing at the worst of times, and never when you want him.</p>

<p>You know what? That’s still a genre of Minecraft joke I still find fresh.</p>

<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/0iO8YW2totM?si=p6WQvk5RgOcvnBT9" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>

<p>To address the Wandering Trader not being predictable, I came up with the idea of a ‘Trader Storehouse’ structure, similar in size and generation as the <a href="https://minecraft.wiki/w/Monster_Room">Monster Room</a>, but all dingy, likely smelly, illuminated by a single lantern, and absolutely stuffed with barrels.</p>

<p>Of course, there’d be all sorts of trader junk in the barrels to steal, but most importantly there was a counter with a countertop bell conspicuously in the centre, inviting the player to give-it-a-ding. Doing so would instantly teleport the Wandering Trader to that bell in a puff of smoke, kind of like when Naruto’s shadow clones appear in that one anime that I can never remember the name of.</p>

<p>The player would be able to take the countertop bell back to their base and have an instant Wandering Trader summoning device.</p>

<hr />

<p>The idea was about as well thought out as any 40 second Minecraft idea, so was destined to fail, but the image of a dingy room crammed with barrels stuck with me.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/barrel/noemeralds.jpeg" alt="An illustration of the Wandering Trader swinging a punch towards the viewer. Behind them is a dingy room filled with jars on shelves." width="600" /><br />
Clearly I find something about traders in dingy rooms appealing as I'd later create this artwork.
</p>

<h2 id="the-barrel-armour">The Barrel Armour</h2>

<p>Again, my memory is fuzzy, so excuse the probably made-up details.</p>

<p>During the entire off-site I was making frequent call-backs with my colleagues to ideas that I had brought up earlier in the day. At some point, I was at a table where we were discussing ideas for armours, or hats, or something that the player could find in a cave and slip into for a more comfortable caving experience.</p>

<p>With barrels still fresh on my mind, I suggested the idea of players wearing <a href="https://en.wikipedia.org/wiki/Bankruptcy_barrel">Bankruptcy Barrels</a>, a joke item of clothing that represents an individual so devoid of Minecraft ores that they can’t even afford real armour.</p>

<p>Surprisingly, this idea actually got some positive reception, and it was enshrined as an idea for our table to present to the rest of the Vanilla team on the off-site.</p>

<h2 id="why-is-the-wearable-barrel-interesting">Why is the wearable Barrel interesting?</h2>

<p>I think what sparked the positive reception was that this idea played with the concept of what is a block versus what is armour. Minecraft has wearable <a href="https://minecraft.wiki/w/Carved_Pumpkin#Helmet">Carved Pumpkin helmets</a>, so the precedent was there, but generally we don’t see much blending between the concepts of Blocks, Mobs, and Items.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/barrel/Steve_wearing_Carved_Pumpkin.png" alt="Minecraft Steve with a Carved Pumpkin helmet." height="200" /><br />
Image courtesy of the <a href="https://minecraft.wiki">minecraft.wiki</a>.
</p>

<p>The simple premise of wearing a Minecraft Barrel also has potential for interesting mechanics: The Barrel is a storage block, so perhaps there’s a concept for carrying a large number of items prior to acquiring Shulker boxes, with the drawback being the player’s arms are inaccessible. We’ve all played stealth games, so perhaps there’s a concept for hiding in a barrel whilst skeletons and zombies creep around you in a cave.</p>

<p>For myself, I had been watching Yogscast TTT videos and find a lot of joy in their usage of the prop-disguiser tool. The idea of disguising as a barrel to confuse other players in multiplayer was very appealing. I also used to play Prop Hunt on Garrys Mod, and playing that in Minecraft with block disguises sounded very fun.</p>

<h2 id="the-only-prototype">The Only Prototype</h2>

<p>The idea was initially thrown into the pile of ‘good’ ideas, and I even went ahead and made a cheeky prototype of what I had in mind.</p>

<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/DyXBJ987Aak?si=-X7hQHw9PSGlVaw5" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>

<p>However, these type of gimmicky toy-ideas tend to be left behind in favour of features that actually have an impact on players for more than 5 minutes. Plus: this not exactly having anything to do with caves (nor cliffs) meant it was an obvious thing to drop.</p>

<p>I remember the prototype didn’t match the expectations of designers: I wanted just the player’s legs to be visible, but the consensus was that the charm is the visual of the player’s head poking out the top, with perhaps their arms stuck out the sides in a T-pose - so it was clear that the amount of discussion and exploration needed here was beyond the value it would provide as a toy.</p>

<h3 id="other-features-of-this-prototype">Other Features of this Prototype</h3>

<p>I added a cute little detail where whatever was on the player’s head slot would be balanced on top of the barrel: so you’d know if the player under it was wearing a Diamond Helmet, or a Carved Pumpkin.</p>

<p>I even made it expandable to any block with the “disguise” tag. This looked cool; with combinations like the Hay Bale with the Carved Pumpkin on an Armor Stand making a sort of scarecrow looking thing.</p>

<p>Mobs could also wear disguise blocks, but they couldn’t attack you when doing so. It was funny being chased by a gang of zombies all trapped in Barrels - even if it had no practical purpose nor balance in terms of combat.</p>

<p>(If I can find a screenshot I’ll edit it into here).</p>

<h2 id="the-fate">The Fate</h2>

<p>The idea was completely killed when it was brought up for technical discussion. At the time, I was new in the Java Edition team, so I wasn’t very clued into the myriad of technical concerns that an idea like this would have, especially for Bedrock Edition.</p>

<p>For instance, players hiding in a block? How would you code that? Is it a new block that remembers which player is hiding in it? How would that block work with resource packs that change textures? Would it reveal all blocks containing players? If it was just a normal block, how would the server remember there’s a player in it? What if another player mined that block? Maybe it should be an entity? But can another player stand on this entity? How do we do that?</p>

<p>And then there’s the concerns for player animations. My prototype hides chunks of the player skin, how does that work for items they are holding? What about other armour pieces? How should these edge cases be coded? What about marketplace items that add geometry to the player? What decides the visible parts?</p>

<p>Now that I’m a tech lead, I would reject this idea for having far too much complexity, given that it was a toy with no natrual interaction with current Minecraft mechanics. The development effort on all fronts is better spent elsewhere.</p>

<h1 id="one-block-at-a-time-2022">One Block At A Time 2022</h1>

<p>Silly ideas tend to get a second chance to live on in the April Fools’ updates, so I saw a great opportunity to really shoe-horn this one into <a href="https://www.minecraft.net/en-us/article/mojang-studios-release-new-astonishing-update">One Block At A Time</a>.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/barrel/aprilis_asinus6.jpg" alt="A Minecraft Creeper staring at a conspicuous Barrel." width="600" /><br />
Sneaky block? What sneaky block?
</p>

<h2 id="the-design">The Design</h2>

<p>Ulraf would be the right person to talk about this, as this April Fools’ was his brainchild, but his guiding principle for us Java devs was “We can pick up Mobs, so just start adding as many Mob-holding abilities as you can think of!”.</p>

<p>I needed to make sure I was shoe-horning a shoe that vaguely fitted with the spirit of these words, so I expanded the inventory from one block in the hand, to also one block on the head (ruining the purity of Ulraf’s vision…), and added the complication of <em>Block-wearing abilities</em>.</p>

<p>Ice on the head would freeze the player, Magma would instantly cause burn damage, and the Barrel would provide the disguise ability.</p>

<h3 id="extra-details">Extra Details</h3>

<p>I hacked in the barrel to disable mob aggression when the player was crouching with it, and also added this hilarious inside-barrel overlay that would instantly appear and confuse the player as the Barrel landed on their head.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/barrel/overlay.png" alt="Staring at some Minecraft Cows from the Barrel." width="600" /><br />
Combined with the sound effect, it made everyone smile the first time they saw this.
</p>

<p>The easiest way to get a block onto your head was to throw the block directly upwards, so chances are the player is looking straight up at the sky when this overlay appears, plunging them in darkness as they wiggle the mouse to figure out what happened.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/barrel/open.png" alt="The underside of the Barrel showing the open texture." width="600" /><br />
The other small detail that I like is how the Barrel "open" texture is used.
</p>

<h1 id="where-is-the-wearable-barrel-now">Where is the Wearable Barrel now?</h1>

<p>The joke has been told now, so I’m satisfied leaving it in One Block At A Time. The Java Edition April Fools’ updates remain available, so we can always go back and play around with it.</p>

<p>Part of me was hoping the community would light up with joy around the Barrel, but that did not happen. Actually that was a learning point: The community explored the April Fools’ update as far as video content creators took them, so a lot of the features ended up being missed for a number of months afterwards as most video content creators only explored about 10 minutes before moving onto more timely/relevant Minecraft updates.</p>

<p><a href="https://www.youtube.com/watch?v=0qYN-vVFZ2M">Pixlriffs has a most epic playthrough of One Block At A Time that I can’t recommend enough</a>. I feel that he exposed a lot of what I believe makes this one of the more important Minecraft updates with the extremely emergent mechanics that he constructed around the raw limitations of only holding One Block At A Time.</p>

<p>Unfortunately the Barrel didn’t make an appearance in his video series, showing how orthogonal it was to not just Minecraft, but also the spirit of One Block At A Time (a toy idea to the very end!).</p>

<hr />

<p>As for the idea within Mojang Studios: Whilst the Wearable Barrel is unlikely to return, some of the ideas and concepts surrounding it have been mentioned in passing. In particular, hiding from mobs seems to evoke a bit of that classic feeling of walling yourself in from a Zombie underground and hiding in pitch darkness until it is safe to flee.</p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[The 2022 April Fools’ update is still my favourite for some Minecraft philosophy reasons, but in particular I snuck my darling Minecraft idea into the joke update.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://felixjones.co.uk/assets/barrel/overlay.png" /><media:content medium="image" url="https://felixjones.co.uk/assets/barrel/overlay.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">The Coolest Tribool</title><link href="https://felixjones.co.uk/2023/11/09/the-coolest-tribool.html" rel="alternate" type="text/html" title="The Coolest Tribool" /><published>2023-11-09T00:00:00+00:00</published><updated>2023-11-09T00:00:00+00:00</updated><id>https://felixjones.co.uk/2023/11/09/the-coolest-tribool</id><content type="html" xml:base="https://felixjones.co.uk/2023/11/09/the-coolest-tribool.html"><![CDATA[<p>A common function in the GBA community is to convert the directional pad buttons into a signed integer value for each axis.</p>

<p>If Left is pressed, a <code class="language-plaintext highlighter-rouge">-1</code> is returned, if Right is pressed, a <code class="language-plaintext highlighter-rouge">+1</code> is returned. If both, or neither, are pressed: <code class="language-plaintext highlighter-rouge">0</code> is returned.</p>

<p>This is often called a “tribool”, AKA a 3-state value.</p>

<p>When represented with <code class="language-plaintext highlighter-rouge">-1</code>, <code class="language-plaintext highlighter-rouge">0</code>, <code class="language-plaintext highlighter-rouge">+1</code>, the tribool can be directly added to a position value to move a character left or right. Very handy.</p>

<h1 id="implementing-tribool">Implementing Tribool</h1>

<p>Assume our tribool is constructed from a bitmask, where bit 0 is <code class="language-plaintext highlighter-rouge">+1</code>, and bit 1 is <code class="language-plaintext highlighter-rouge">-1</code>.</p>

<h2 id="first-version">First version</h2>

<p>Most programmers would probably write something like this as their first attempt:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">tribool</span><span class="p">(</span><span class="kt">int</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">int</span> <span class="n">bit0</span> <span class="o">=</span> <span class="n">mask</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">const</span> <span class="kt">int</span> <span class="n">bit1</span> <span class="o">=</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">;</span>
    
    <span class="k">if</span> <span class="p">(</span><span class="n">bit0</span> <span class="o">==</span> <span class="n">bit1</span><span class="p">)</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">bit0</span> <span class="o">?</span> <span class="mi">1</span> <span class="o">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Compiled with GCC <code class="language-plaintext highlighter-rouge">-O2</code> the 32-bit ARM code is:</p>

<pre><code class="language-arm">tribool:
        asr     r3, r0, #1
        and     r3, r3, #1
        and     r0, r0, #1
        cmp     r0, r3
        beq     .L3
        cmp     r0, #0
        mvneq   r0, #0
        bx      lr
.L3:
        mov     r0, #0
        bx      lr
</code></pre>

<h2 id="tonclib-version">Tonclib version</h2>

<p>The <a href="https://github.com/devkitPro/libtonc">libtonc</a> implementation looks like:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">tribool</span><span class="p">(</span><span class="kt">int</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">int</span> <span class="n">bit0</span> <span class="o">=</span> <span class="n">mask</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">const</span> <span class="kt">int</span> <span class="n">bit1</span> <span class="o">=</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">;</span>

    <span class="k">return</span> <span class="n">bit0</span> <span class="o">-</span> <span class="n">bit1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Compiled with GCC <code class="language-plaintext highlighter-rouge">-Og</code> the 32-bit ARM code is:</p>

<pre><code class="language-arm">tribool:
        and     r3, r0, #1
        asr     r0, r0, #1
        and     r0, r0, #1
        sub     r0, r3, r0
        bx      lr
</code></pre>

<p>This looks astonishingly optimised, however I suspected we could do better.</p>

<h1 id="sign-extending">Sign extending</h1>

<p>On the GBA the key indices for each axis on the dpad, and the shoulder buttons, are next to each other.</p>

<p>I noticed that simply sign-extending the upper bit will get us somewhat close to a tribool implementation:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">almost_tribool</span><span class="p">(</span><span class="kt">int</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&lt;&lt;</span> <span class="mi">30</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">30</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>For an 8-bit number, this sign extend produces the following states:</p>

<table>
  <thead>
    <tr>
      <th>2-bit Mask</th>
      <th>8-bit Sign Extended</th>
      <th>“Tribool” State</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0b00</td>
      <td>0b00000000</td>
      <td>0</td>
    </tr>
    <tr>
      <td>0b01</td>
      <td>0b00000001</td>
      <td>1</td>
    </tr>
    <tr>
      <td>0b10</td>
      <td>0b11111110</td>
      <td>-2</td>
    </tr>
    <tr>
      <td>0b11</td>
      <td>0b11111111</td>
      <td>-1</td>
    </tr>
  </tbody>
</table>

<p>Unfortunately this does not respect the exclusivity requirement of our tribool function: When both bits are equal (<code class="language-plaintext highlighter-rouge">0b00</code> or <code class="language-plaintext highlighter-rouge">0b11</code>), the function must always return <code class="language-plaintext highlighter-rouge">0</code>.</p>

<p>But this is close, and for original GBA hardware where it is physically impossible to hit both left and right buttons at the same time this almost works (as long as you only do sign comparisons or compare against zero).</p>

<p>For anyone interested the GCC <code class="language-plaintext highlighter-rouge">-Og</code> 32-bit ARM code is:</p>

<pre><code class="language-arm">almost_tribool:
        lsls    r0, r0, #30
        asrs    r0, r0, #30
        bx      lr
</code></pre>

<p>A simple sign-extend.</p>

<h2 id="fixing-up-the-bits">Fixing up the bits</h2>

<p>My first instinct was to analyse the possible states, and figure out how to manually fix the <code class="language-plaintext highlighter-rouge">-2</code> and <code class="language-plaintext highlighter-rouge">-1</code> states.</p>

<p>I noticed that just adding <code class="language-plaintext highlighter-rouge">1</code> gets these into range, however this breaks the <code class="language-plaintext highlighter-rouge">0</code> and <code class="language-plaintext highlighter-rouge">1</code> cases:</p>

<table>
  <thead>
    <tr>
      <th>2-bit Mask</th>
      <th>8-bit Sign Extended + <code class="language-plaintext highlighter-rouge">1</code></th>
      <th>“Tribool” State</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0b00</td>
      <td>0b00000001</td>
      <td>1</td>
    </tr>
    <tr>
      <td>0b01</td>
      <td>0b00000010</td>
      <td>2</td>
    </tr>
    <tr>
      <td>0b10</td>
      <td>0b11111111</td>
      <td>-1</td>
    </tr>
    <tr>
      <td>0b11</td>
      <td>0b00000000</td>
      <td>0</td>
    </tr>
  </tbody>
</table>

<p>So we should only add <code class="language-plaintext highlighter-rouge">1</code> for the negative cases, conveniently the cases with a sign-bit set:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">tribool</span><span class="p">(</span><span class="kt">int</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">mask</span> <span class="o">=</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&lt;&lt;</span> <span class="mi">30</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">30</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">mask</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">mask</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Compiled with GCC <code class="language-plaintext highlighter-rouge">-O1</code> the 32-bit ARM code is perfect:</p>

<pre><code class="language-arm">tribool:
        lsl     r0, r0, #30
        asrs    r0, r0, #30
        addmi   r0, r0, #1
        bx      lr
</code></pre>

<p>The <code class="language-plaintext highlighter-rouge">addmi</code> instruction is conditionally executed only when the <code class="language-plaintext highlighter-rouge">mi</code> CPU flag (the minus flag) is set, which the preceeding <code class="language-plaintext highlighter-rouge">asrs</code> instruction sets if the result or arithmetically shifting right is a negative/minus number.</p>

<p>The 16-bit thumb code with GCC <code class="language-plaintext highlighter-rouge">-O1</code> is equally as good:</p>

<pre><code class="language-arm">tribool:
        lsls    r3, r0, #30
        asrs    r0, r3, #30
        lsrs    r3, r3, #31
        adds    r0, r0, r3
        bx      lr
</code></pre>

<p>In this code, the second <code class="language-plaintext highlighter-rouge">lsrs</code> converts the sign bit into the number <code class="language-plaintext highlighter-rouge">1</code> and adds that to the original value.</p>

<h3 id="what-about--og">What about <code class="language-plaintext highlighter-rouge">-Og</code>?</h3>

<p>Notice that I showed the GCC <code class="language-plaintext highlighter-rouge">-O1</code> assembly output for the fixed implementation of sign-extended tribool.</p>

<p>For GDB debugging on embedded systems, especially retro consoles like the GBA, you should really be using <code class="language-plaintext highlighter-rouge">-Og</code>.</p>

<p>GCC <code class="language-plaintext highlighter-rouge">-Og</code> 32-bit ARM:</p>

<pre><code class="language-arm">tribool:
        lsl     r0, r0, #30
        asrs    r0, r0, #30
        bxpl    lr
        add     r0, r0, #1
        bx      lr
</code></pre>

<p>GCC <code class="language-plaintext highlighter-rouge">-Og</code> 16-bit thumb:</p>

<pre><code class="language-arm">tribool:
        lsls    r3, r0, #30
        asrs    r0, r3, #30
        cmp     r3, #0
        bge     .L1
        adds    r0, r0, #1
.L1:
        bx      lr
</code></pre>

<p>The ARM code isn’t too bad, with <code class="language-plaintext highlighter-rouge">bxpl</code> returning if the result is positive, but the thumb code now has a full-fat branch.</p>

<p>We can further fix this by explicitly writing out the 16-bit thumb logic in C:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">tribool</span><span class="p">(</span><span class="kt">int</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">mask</span> <span class="o">=</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&lt;&lt;</span> <span class="mi">30</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">30</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">fix</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span> <span class="n">mask</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">mask</span> <span class="o">+</span> <span class="n">fix</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Compiled with GCC <code class="language-plaintext highlighter-rouge">-Og</code> 16-bit thumb:</p>

<pre><code class="language-arm">tribool:
        lsls    r3, r0, #30
        asrs    r0, r3, #30
        lsrs    r3, r3, #31
        adds    r0, r0, r3
        bx      lr
</code></pre>

<p>Compiled with GCC <code class="language-plaintext highlighter-rouge">-Og</code> 32-bit ARM:</p>

<pre><code class="language-arm">tribool:
        lsl     r0, r0, #30
        lsr     r3, r0, #31
        add     r0, r3, r0, asr #30
        bx      lr
</code></pre>

<p>This is the best we can get with 32-bit ARM, with 1 instruction fewer than Tonclib.</p>

<p>For 16-bit thumb, there is one more optimisation available.</p>

<h1 id="register-pressure">Register pressure</h1>

<p>There’s never enough registers on a CPU, so often a lot of time is spent juggling registers on the stack.</p>

<p>If we’re inlining these functions (which for sometihng this small, you probably should be) then optimising how many registers are used becomes important.</p>

<p>The problem is the temporary used:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">fix</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span> <span class="n">mask</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">;</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">fix</code> value depends on <code class="language-plaintext highlighter-rouge">mask</code>, and our <code class="language-plaintext highlighter-rouge">mask + fix</code> return value depends on both, so two registers will be used.</p>

<p>If we could remove <code class="language-plaintext highlighter-rouge">fix</code> then the compiler will be able to operate solely on the <code class="language-plaintext highlighter-rouge">mask</code>.</p>

<h2 id="analysis-of-the-bits">Analysis of the bits</h2>

<p>Looking back at the 8-bit sign extended binary:</p>

<table>
  <thead>
    <tr>
      <th>2-bit Mask</th>
      <th>8-bit Sign Extended</th>
      <th>“Tribool” State</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0b00</td>
      <td>0b00000000</td>
      <td>0</td>
    </tr>
    <tr>
      <td>0b01</td>
      <td>0b00000001</td>
      <td>1</td>
    </tr>
    <tr>
      <td>0b10</td>
      <td>0b11111110</td>
      <td>-2</td>
    </tr>
    <tr>
      <td>0b11</td>
      <td>0b11111111</td>
      <td>-1</td>
    </tr>
  </tbody>
</table>

<p>The two correct states (<code class="language-plaintext highlighter-rouge">0</code> and <code class="language-plaintext highlighter-rouge">1</code>) only differ by bit index 0 (the lowest bit), and the two incorrect states (<code class="language-plaintext highlighter-rouge">-2</code> and <code class="language-plaintext highlighter-rouge">-1</code>) differ by <em>the same</em> bit index 0.</p>

<p>If we were to shift right by 1 bit with sign extend then we can separate the correct and incorrect states into two values:</p>

<table>
  <thead>
    <tr>
      <th>2-bit Mask</th>
      <th>8-bit Sign Extended</th>
      <th>Shifted right 1</th>
      <th>Fix State</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0b00</td>
      <td>0b00000000</td>
      <td>0b00000000</td>
      <td>0</td>
    </tr>
    <tr>
      <td>0b01</td>
      <td>0b00000001</td>
      <td>0b00000000</td>
      <td>0</td>
    </tr>
    <tr>
      <td>0b10</td>
      <td>0b11111110</td>
      <td>0b11111111</td>
      <td>-1</td>
    </tr>
    <tr>
      <td>0b11</td>
      <td>0b11111111</td>
      <td>0b11111111</td>
      <td>-1</td>
    </tr>
  </tbody>
</table>

<p>The correct states are now <code class="language-plaintext highlighter-rouge">0</code>, and the incorrect states are now <code class="language-plaintext highlighter-rouge">-1</code>, we can subtract by this <code class="language-plaintext highlighter-rouge">-1</code> to apply our <code class="language-plaintext highlighter-rouge">+ 1</code> fix from earlier:</p>

<table>
  <thead>
    <tr>
      <th>2-bit Mask</th>
      <th>Sign Extended</th>
      <th>Fix State</th>
      <th>Sign Extended - Fix State</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0b00</td>
      <td>0</td>
      <td>0</td>
      <td>0 - 0 = <strong>0</strong></td>
    </tr>
    <tr>
      <td>0b01</td>
      <td>1</td>
      <td>0</td>
      <td>1 - 0 = <strong>1</strong></td>
    </tr>
    <tr>
      <td>0b10</td>
      <td>-2</td>
      <td>-1</td>
      <td>-2 - -1 = <strong>-1</strong></td>
    </tr>
    <tr>
      <td>0b11</td>
      <td>-1</td>
      <td>-1</td>
      <td>-1 - -1 = <strong>0</strong></td>
    </tr>
  </tbody>
</table>

<p>And now we have our desired tribool.</p>

<p>The C for this is:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">tribool</span><span class="p">(</span><span class="kt">int</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">mask</span> <span class="o">=</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&lt;&lt;</span> <span class="mi">30</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">30</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">mask</span> <span class="o">-</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>But wait, this still internally requires a temporary register for <code class="language-plaintext highlighter-rouge">mask &gt;&gt; 1</code> to be added to the original <code class="language-plaintext highlighter-rouge">mask</code>, so all we’ve done is hide the register in C.</p>

<h2 id="ones-complement-rabbit-hole">Ones’ complement rabbit hole</h2>

<p>After staring at the binary for a while I noticed that the two incorrect states are <strong>ones’ complement</strong> of the actual state I needed them to be in.</p>

<p>So this whole time I was trying to figure out how to convert 2-bit ones’ complement negative numbers into 2-bit twos’ complement.</p>

<p>The Wikipedia articles for both ones’ complement and two’s complement has good information:</p>

<ul>
  <li><a href="https://en.wikipedia.org/wiki/Ones%27_complement">Ones’ complement</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Two%27s_complement">Two’s complement</a></li>
</ul>

<p>This took me down the rabbit hole of trying to convert using a combination of bit flips (<code class="language-plaintext highlighter-rouge">~mask</code>) and two’s complement negation (<code class="language-plaintext highlighter-rouge">-mask</code>), but nothing I tried was an improvement.</p>

<h1 id="the-coolest-tribool">The coolest tribool</h1>

<p>I went back to the analysis of the <code class="language-plaintext highlighter-rouge">+ 1</code> fix:</p>

<table>
  <thead>
    <tr>
      <th>2-bit Mask</th>
      <th>8-bit Sign Extended + <code class="language-plaintext highlighter-rouge">1</code></th>
      <th>“Tribool” State</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0b00</td>
      <td>0b00000001</td>
      <td>1</td>
    </tr>
    <tr>
      <td>0b01</td>
      <td>0b00000010</td>
      <td>2</td>
    </tr>
    <tr>
      <td>0b10</td>
      <td>0b11111111</td>
      <td>-1</td>
    </tr>
    <tr>
      <td>0b11</td>
      <td>0b00000000</td>
      <td>0</td>
    </tr>
  </tbody>
</table>

<p>After spending so long staring at the bits, I noticed something: The values I was looking for were right there all along!</p>

<table>
  <thead>
    <tr>
      <th>2-bit Mask</th>
      <th>8-bit Sign Extended + <code class="language-plaintext highlighter-rouge">1</code></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0b00</td>
      <td>0b00000<strong>00</strong>1</td>
    </tr>
    <tr>
      <td>0b01</td>
      <td>0b00000<strong>01</strong>0</td>
    </tr>
    <tr>
      <td>0b10</td>
      <td>0b11111<strong>11</strong>1</td>
    </tr>
    <tr>
      <td>0b11</td>
      <td>0b00000<strong>00</strong>0</td>
    </tr>
  </tbody>
</table>

<p>Just right shifting one more place (with sign extend) gets the results I had been looking for.</p>

<table>
  <thead>
    <tr>
      <th>2-bit Mask</th>
      <th>8-bit Sign Extended + <code class="language-plaintext highlighter-rouge">1</code></th>
      <th>Shift Right</th>
      <th>Tribool State</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0b00</td>
      <td>0b00000001</td>
      <td>0b00000000</td>
      <td>0</td>
    </tr>
    <tr>
      <td>0b01</td>
      <td>0b00000010</td>
      <td>0b00000001</td>
      <td>1</td>
    </tr>
    <tr>
      <td>0b10</td>
      <td>0b11111111</td>
      <td>0b11111111</td>
      <td>-1</td>
    </tr>
    <tr>
      <td>0b11</td>
      <td>0b00000000</td>
      <td>0b00000000</td>
      <td>0</td>
    </tr>
  </tbody>
</table>

<p>The C for this is the obvious:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">tribool</span><span class="p">(</span><span class="kt">int</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">mask</span> <span class="o">=</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&lt;&lt;</span> <span class="mi">30</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">30</span><span class="p">;</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">mask</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Compiled with GCC <code class="language-plaintext highlighter-rouge">-Og</code> 16-bit thumb:</p>

<pre><code class="language-arm">tribool:
        lsls    r0, r0, #30
        asrs    r0, r0, #30
        adds    r0, r0, #1
        asrs    r0, r0, #1
        bx      lr
</code></pre>

<p>Compiled with GCC <code class="language-plaintext highlighter-rouge">-Og</code> 32-bit ARM:</p>

<pre><code class="language-arm">tribool:
        lsl     r0, r0, #30
        asr     r0, r0, #30
        add     r0, r0, #1
        asr     r0, r0, #1
        bx      lr
</code></pre>

<p>Notice that the assembly for both thumb and ARM only operates on <code class="language-plaintext highlighter-rouge">r0</code>, which is the input parameter <code class="language-plaintext highlighter-rouge">mask</code>.</p>

<h2 id="final-implementation">Final implementation</h2>

<p>32-bit ARM mode has more available registers than 16-bit thumb, so optimising for register pressure isn’t necessarily the best choice.</p>

<p>My final implementation selects between optimising for code size with 32-bit ARM, and register pressure for 16-bit thumb.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">tribool</span><span class="p">(</span><span class="kt">int</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">mask</span> <span class="o">=</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&lt;&lt;</span> <span class="mi">30</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">30</span><span class="p">;</span> <span class="c1">// Sign extend high bit</span>
<span class="cp">#if defined(__arm__) &amp;&amp; !defined(__thumb__)
</span>    <span class="k">return</span> <span class="n">mask</span> <span class="o">-</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">);</span> <span class="c1">// Optimise for code size</span>
<span class="cp">#else
</span>    <span class="k">return</span> <span class="p">(</span><span class="n">mask</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// Optimise for register pressure</span>
<span class="cp">#endif
</span><span class="p">}</span>
</code></pre></div></div>

<p>Compiling for GCC <code class="language-plaintext highlighter-rouge">-Og</code> on x86_64 will select the register pressure optimisation:</p>

<pre><code class="language-x86asm">tribool:
        mov     eax, edi
        sal     eax, 30
        sar     eax, 30
        add     eax, 1
        sar     eax
        ret
</code></pre>

<h2 id="inverting-the-tribool">Inverting the tribool</h2>

<p>The GBA keypad register is actually bit inverted to what most programmers would expect, so a button pressed is <code class="language-plaintext highlighter-rouge">0</code>, and a button released is <code class="language-plaintext highlighter-rouge">1</code>.</p>

<p>Most developers invert the keypad mask after reading it, so they can test <code class="language-plaintext highlighter-rouge">mask &amp; KEYLEFT</code> and get the result they expect.</p>

<p>This extra invert isn’t strictly necessary (especially if you’re using C++ which can wrap the raw data with accessing member functions), but the tribool implementation needs to be inverted to account for <code class="language-plaintext highlighter-rouge">0</code> being our “true” value, and <code class="language-plaintext highlighter-rouge">1</code> being our “false” value.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">inv_tribool</span><span class="p">(</span><span class="kt">int</span> <span class="n">mask</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">mask</span> <span class="o">=</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&lt;&lt;</span> <span class="mi">30</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">30</span><span class="p">;</span> <span class="c1">// Sign extend high bit</span>
<span class="cp">#if defined(__arm__) &amp;&amp; !defined(__thumb__)
</span>    <span class="k">return</span> <span class="p">(</span><span class="n">mask</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="n">mask</span><span class="p">;</span> <span class="c1">// Optimise for code size</span>
<span class="cp">#else
</span>    <span class="k">return</span> <span class="p">(</span><span class="mi">0</span> <span class="o">-</span> <span class="n">mask</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// Optimise for register pressure</span>
<span class="cp">#endif
</span><span class="p">}</span>
</code></pre></div></div>

<p>Notice the symmetry with the regular function.</p>

<p>The thumb and ARM assembly is just as sensible:</p>

<p>16-bit thumb:</p>

<pre><code class="language-arm">inv_tribool:
        lsls    r0, r0, #30
        asrs    r0, r0, #30
        rsbs    r0, r0, #0
        asrs    r0, r0, #1
        bx      lr
</code></pre>

<p>32-bit ARM:</p>

<pre><code class="language-arm">inv_tribool:
        lsl     r0, r0, #30
        asr     r3, r0, #31
        sub     r0, r3, r0, asr #30
        bx      lr
</code></pre>

<h1 id="compiler-explorer-link">Compiler Explorer link</h1>

<p><a href="https://godbolt.org/z/z6Y6efb9h">godbolt.org/z/z6Y6efb9h</a></p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[A common function in the GBA community is to convert the directional pad buttons into a signed integer value for each axis.]]></summary></entry><entry><title type="html">Mob Vote 2023 post-mortem</title><link href="https://felixjones.co.uk/2023/10/16/mob-vote-23.html" rel="alternate" type="text/html" title="Mob Vote 2023 post-mortem" /><published>2023-10-16T00:00:00+00:00</published><updated>2023-10-16T00:00:00+00:00</updated><id>https://felixjones.co.uk/2023/10/16/mob-vote-23</id><content type="html" xml:base="https://felixjones.co.uk/2023/10/16/mob-vote-23.html"><![CDATA[<p>Yesterday was the canonical two-thousand-and-twenty-third Mob Vote.</p>

<div id="wrapper" style="display:inline-block">
    <img style="float: left; padding: 10px;" src="https://felixjones.co.uk/assets/mobvote23/(Toulouse)_Tibere_-_Musee_Saint-Raymond_Ra_342_b.jpg" alt="Tiberius Julius Caesar Augustus." height="128" /><br />
    <p>
    Did you know: The first mob vote was hosted by Roman emporer Tiberius Julius Augustus in the year 1 AD to decide which of three beasts shall be thrown into Gladiatorial battle against Stevus Maximus Aurus; a fighter who gained fame through defeating a squid using nothing but a fishing rod. Probably.
    </p>
</div>

<p>Opinions expressed here are my own, they are not representative of Mojang Studios, nor the Minecraft team.</p>

<p>Full transparency: I do not have any <em>direct</em> involvement in Minecraft Live, nor the mob voting itself, so I am likely talking out of ignorance regarding how things work and my opinions are probably going to be garbage as a result of that ¯\_(ツ)_/¯</p>

<h1 id="what-was-i-involved-with">What <em>was</em> I involved with?</h1>

<p>Unlike previous years; this year I didn’t first learn about the mobs via drinking boxed wine with colleagues in Vasaparken. I had the Bedrock Gameplay Tech Lead responsibility of signing off on the mob proposals, giving me the power to make things very difficult for the mob designers by rejecting their ideas with any kind of tech related excuse - if I <em>really</em> wanted to &gt;:D</p>

<p>Specifically what I was signing off on was “is this idea technically feasible given our time and resources”.</p>

<h1 id="my-office-conversations">My Office Conversations</h1>

<h2 id="which-mob-will-you-vote-for">Which mob will you vote for?</h2>

<p>Between the handful of colleagues I asked, it seemed like the battle will be between the Crab and the Penguin.</p>

<p>Both sides argued that their mob was “cute”, which seems to be the deciding factor amongst the handful of Mojang staff that happened to be in conversation with me.</p>

<h2 id="which-mob-do-you-think-will-win">Which mob do you <em>think</em> will win?</h2>

<p>This is a very different question, but again it seemed like the battle will be between the Crab and the Penguin.</p>

<p>The arguments were:</p>

<ul>
  <li>Crab has a utility to help players, and players always vote for the useful mob</li>
  <li>Penguin is a real cutie, and players always vote for the cute mob</li>
</ul>

<p>I felt pretty alone when I argued the Armadillo would win, but who’s laughing now?</p>

<h1 id="the-armadillo-won-the-mob-vote">The Armadillo Won the Mob Vote</h1>

<p align="center">
<img src="https://felixjones.co.uk/assets/mobvote23/armadillo.webp" alt="The Armadillo won the mob vote." width="600" /><br />
The Armadillo won the mob vote.
</p>

<h1 id="were-the-2023-mobs-better-balanced">Were the 2023 Mobs Better Balanced?</h1>

<p>Again: I wasn’t involved in this, other than signing off on the technical proposals, so I have no clue how much thought or effort was put into balancing the mobs versus previous years, but as a Minecraft fan it looks to me that some serious effort was put into avoiding having “one obvious choice” that I believe affected previous mob votes.</p>

<p><img src="https://felixjones.co.uk/assets/mobvote23/balance.jpg" alt="Meme of Thanos balancing a knife, but I put the crab and the penguin on the ends of the knife. The armadillo is confused." width="600" /><br /></p>

<p>I do wonder if the mobs have indeed been simplified versus the Allay or Sniffer in terms of complexity to keep things balanced. Of course, the winning mob will probably have a load more complexity thrown into it as its design is explored (I hope not because that means more work…), but I believe what we presented this year was kept simple and that’s what provided the balance.</p>

<p>We got the mob, a quirk, the location, and 1 feature:</p>

<table>
  <thead>
    <tr>
      <th style="text-align: right">Mob</th>
      <th>Quirk</th>
      <th>Biome</th>
      <th>Feature</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">Penguin</td>
      <td>Social amphibian</td>
      <td>Stony shores</td>
      <td>Somehow makes boats fast</td>
    </tr>
    <tr>
      <td style="text-align: right">Armadillo</td>
      <td>Curls into a ball</td>
      <td>Savanna</td>
      <td>Scute makes wolf armour</td>
    </tr>
    <tr>
      <td style="text-align: right">Crab</td>
      <td>It’s a crab.</td>
      <td>Mangrove swamp</td>
      <td>Somehow claw places blocks further away</td>
    </tr>
  </tbody>
</table>

<h2 id="a-world-without-one-obvious-choice">A world without “one obvious choice”</h2>

<p>Last year I wrote that I saw a handful of comments along the lines of “But seeing the other two mobs lose makes me upset”, and I specifically said “I’m probably not communicating my point here very well, probably because I need more time to think on it.”</p>

<p>I now think that this sentiment from years past came from individuals who believed past mob votes were balanced and were faced with the reality that no matter the winner: it is a 66% loss - and I believe with the mobs being even more balanced this year this sentiment grew to be the dominant discussion on Twitter.</p>

<p>If there was one obvious choice, then the results of the vote is not a 66% loss, it’s a 0% loss because one of the mobs was clearly better than all the others, and comparatively fewer people would be upset about that.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/mobvote23/yeetingmobs.jpg" alt="The ceremonial yeeting of the mobs." width="600" /><br />
The ceremonial yeeting of the mobs.
</p>

<p>I think this also plays into the sentiment of “the mob vote just divides the community”. If all mobs had a 33% chance of winning, then the community would be divided into thirds, each third championing their mob.</p>

<p>Both of these sentiments are what I’ve personally seen on my Twitter feed this year, leading me to conclude that we got the balance quite close.</p>

<h2 id="why-did-the-armadillo-win">Why did the Armadillo win?</h2>

<p>If the mobs were perfectly balanced, then the vote would tie on a 33% split each (which would have been incredible).</p>

<p>I remember leaving the meeting where the mobs were first presented to me for tech approval, turning to someone and saying “The Armadillo will win because of the Wolf armour”.</p>

<p>I asked my Armadillo-voting followers for some info on why they chose this mob and I’ve seen two major points:</p>

<h3 id="savanna-is-empty">Savanna is empty</h3>

<p>I’ve seen comments that the savanna is empty, lacks identity, lacks a mob, and in general “needs an update”.</p>

<p>Indeed, adding a unique mob to this biome will help, but I’d argue the same applies for the Penguin with the stony shores - that being said the savanna is a more visually interesting biome to build in versus the stony shore.</p>

<h3 id="wolf-armour">Wolf Armour</h3>

<p>I’m probably cherry picking this reason because it’s the one I predicted, but to my, rather-biased, eyes it does indeed look like wolf armour was the deciding factor.</p>

<p>I believe more wolf variations (more specifically, dog breeds) is a very popular suggestion from the community, and in general players care a lot for their Minecraft pets, so with wolf armour taking a step towards pet accessories it probably provides more empathetic theming than a crab claw and boats.</p>

<p>The actual protection the armour provides is important, too, but I wouldn’t be surprised if players are more interested in the aesthetic potential.</p>

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">The armadillo received over 40% of the over 5 million votes! 📷<br /> <br />Mob Vote 2023 results: <br />Armadillo – 42.3% <br />Crab – 32.5%<br />Penguin – 25.2%<a href="https://twitter.com/hashtag/MinecraftLive?src=hash&amp;ref_src=twsrc%5Etfw">#MinecraftLive</a> 🎉 <a href="https://t.co/WmhKVJWJfc">pic.twitter.com/WmhKVJWJfc</a></p>&mdash; Minecraft (@Minecraft) <a href="https://twitter.com/Minecraft/status/1713618649846866367?ref_src=twsrc%5Etfw">October 15, 2023</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<h1 id="more-community-reactions">More Community Reactions</h1>

<p><img src="https://felixjones.co.uk/assets/mobvote23/crab.webp" alt="The Crab did not win the vote." width="600" /><br /></p>

<p>Important! I am not part of the Mojang community team: I am just a dude on Twitter, picking his nose as he scrolls through Minecraft tweets, like any other Minecraft player.</p>

<p>I’ve tried to compile some of the reactions I’ve personally seen, with some of my personal thoughts.</p>

<h2 id="mojang-is-locking-these-crucial-features-behind-the-mob-vote">Mojang is locking these crucial features behind the mob vote</h2>

<p>I was surprised to see this comment appear in Twitter, because personally I don’t believe these features to be crucial, and I think that’s important for a mob vote specifically because Mojang would otherwise be locking crucial features behind a vote.</p>

<p>It’s pretty easy to use the arguments that players have presented against each mob to counter the idea that these are crucial features:</p>

<ul>
  <li>“Crab-claw reach can be achieved by moving closer”</li>
  <li>“If you need to protect your wolf, you’d leave it at home”</li>
  <li>“Dolphins can already speed up swimming”</li>
</ul>

<p>That being said, I think there is a learning <em>somewhere</em> here for the Minecraft team regarding the perception of features being critical to the game.</p>

<h2 id="players-who-dont-even-play-minecraft-that-much-shouldnt-be-allowed-to-vote">Players who don’t even play Minecraft that much shouldn’t be allowed to vote</h2>

<p>An evolution of “no votes from people who don’t own Minecraft”. I have the (very) controversial opinion that even people who watch Minecraft videos without owning the game should be allowed to vote for which mob their favourite content creator gets to interact with.</p>

<p>It seems like a mistake to gate keep the mob vote behind play time, although perhaps some kind of interesting game could be made out of this: The more Diamonds you mine the more votes you get? I can imagine this working with the Bedrock Mob Vote map, where perhaps players could take part in an Infiniminer style PvP game of mine the most Diamonds, which are then traded in for mob votes.</p>

<p>Maybe Mojang should provide some kind of test to see how pro a Minecraft player is before they can vote? I don’t think so.</p>

<h2 id="players-always-vote-for-the-cute-mob">Players always vote for the cute mob</h2>

<p>I think this is more in vein with why I think Wolf armour was a significant factor, where players are voting for something that they can empathise with.</p>

<p>That being said, the Penguin and Crab are both also rather cute.</p>

<p>As I wrote above: the office prediction was that the Crab and Penguin will be split on the argument of Utility vs Cute.</p>

<p>Looking at the 2020 vote: the content creator communities really gathered around and agreed on the Iceologer as being the “correct” choice to vote for. Most of the discussion I saw were around the utility provided by a hostile mob and whatever item it would probably drop, and I remember in the office we expected an Iceologer sweep, to the point where <a href="https://twitter.com/_ulraf_">Ulraf</a>’s reaction when unveiling the Glow Squid was a genuine reaction of surprise. Wait, was the Glow Squid more cute than the Moobloom?</p>

<p>Perhaps cute does trump utility, but I’m not sure that’s a <em>bad</em> reason to vote for a mob.</p>

<p>The mob is going to be in the game for another 85 years or something, so it should probably be one that players enjoy just hanging around and seeing for the long-run. Chances are: any utility provided will be made obsolete by some random update made within the next 50 years.</p>

<p>This probably speaks to the different ways that players play the game: Some players really do focus on the technical aspects, where utility is the most important factor.</p>

<p>If all mobs were equally cute as they were useful, then we’d be golden.</p>

<h2 id="mojang-staff-shouldnt-be-allowed-to-vote">Mojang staff shouldn’t be allowed to vote</h2>

<p>Whilst this one is pretty silly as there’s millions more players than there are staff at Mojang (let alone, people in the Minecraft team), there is probably something to be said about Mojang staff supporting particular mobs on Twitter.</p>

<p>Mojang staff are likely to have inside information, and perhaps there is a biased preference that the Minecraft team would rather work on one mob than the other, so then there’s motivation to encourage your following to vote for your mob of choice.</p>

<p>Of course, this isn’t a sensible line of thinking. The reality is only a handful of people at Mojang are involved with the mobs themselves, and the vast, vast majority of Minecraft players have no social interaction with any Mojang staff.</p>

<p>Plus, it’s just the Minecraft mob vote: It really doesn’t matter.</p>

<h1 id="would-we-be-better-without-a-mob-vote">Would we be better without a Mob Vote?</h1>

<p><img src="https://felixjones.co.uk/assets/mobvote23/penguin.webp" alt="The Penguin did not win the vote." width="600" /><br /></p>

<p>On my personal Twitter, I encountered a lot of individuals expressing the sentiment I mentioned above: The mob vote is heart breaking because no matter which mob wins, it’s a 66% loss with the other two mobs.</p>

<p>This naturally led to “Give us all three mobs this year”, and then “Unpaid modders can add these mobs to the game within hours”.</p>

<p>There’s even a petition to this endeavour, which has gone quite viral.</p>

<p>A lot has already been said about comparing skilled modders vs Mojang elsewhere, including my post last year (that you should read), but I’ll cover one part from last year’s post-mortem again here:</p>

<h2 id="why-have-a-mob-vote">Why have a mob vote?</h2>

<p>Like the rest of this post, the following is my personal opinion and does not reflect the opinions of Mojang Studios nor the Minecraft team.</p>

<p>For many people, the idea of developing a video game, or working in the games industry, is a far-off dream and many write it off as an impossibility. The mob vote is the chance for players to influence the biggest video game in human history.</p>

<p>When I think of the mob vote, I think about all the offline communities talking about Minecraft and discussing which mob to vote for and why. Most Minecraft fans do not have Twitter, or Discord, or a voice on YouTube; they are with their friends talking about Minecraft, and they’re hopefully talking about the experiences that a mob brings to their game.</p>

<p>Maybe they talk about the game design, maybe the artwork, maybe the personality in the animations, or they’re focused on the utility that the mob brings to their game. All of these are game development competencies - and players’ discussions and explorations get to be applied with their mob vote: influencing the development of Minecraft.</p>

<p>It’s a tiny taste of being a game developer: Mojang has the unique opportunity to sow that seed into millions of Minecraft players across the planet once a year. We’re up here with the best game ever made and we should be inviting others to join us. Starting with the players who aren’t even thinking about being game developers, but are currently talking about the design of a Minecraft mob with their friends right before the mob vote.</p>

<p>I admit, it’s a very idealistic way of looking at the Minecraft mob vote. Pessimistically, it’s just community engagement, but to me it’s one of those moments where we build a better world.</p>

<p>In my personal opinion: removing the mob vote would be a net loss.</p>

<hr />

<p>Just a few of my thoughts on the Minecraft 2023 Mob Vote. If you want to hear the rest of my thoughts, then join Mojang, get your NDA signed, and ask me in person.</p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[1 year later, 1 more Mob Vote post-mortem]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://felixjones.co.uk/assets/mobvote23/armadillo.webp" /><media:content medium="image" url="https://felixjones.co.uk/assets/mobvote23/armadillo.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Krispig Blomkål recipe - Chef Felix</title><link href="https://felixjones.co.uk/2023/02/20/krispig-blomkal.html" rel="alternate" type="text/html" title="Krispig Blomkål recipe - Chef Felix" /><published>2023-02-20T00:00:00+00:00</published><updated>2023-02-20T00:00:00+00:00</updated><id>https://felixjones.co.uk/2023/02/20/krispig-blomkal</id><content type="html" xml:base="https://felixjones.co.uk/2023/02/20/krispig-blomkal.html"><![CDATA[<p>Ah, the old cauliflower. Did you know that <a href="https://translate.google.com/?sl=en&amp;tl=sv&amp;text=flower">the Swedish for flower is blomma</a>? Did you also know that <a href="https://translate.google.com/?sl=en&amp;tl=sv&amp;text=cabbage">the Swedish for cabbage is kål</a>?</p>

<p>And did you know that cauliflower, coleslaw, and kale all come from the same Latin word “caulae”?</p>

<p>That’s right: Blomkål is flower-kale, or flower-cauli, or cauliflower.</p>

<p>A while back we used Hello Fresh (not sponsored) for a few months, and this is one of the better recipes that we got, to the point where I’ve cooked it more times than I’ve counted. Unfortunately Hello Fresh’s instructions are close to garbage (do they even account for ingredient preperation time???), not to mention my recipe is in Swedish so I can’t even understand the instructions.</p>

<p>I’ve decided to type it up proper and translate it. I’ll add my own artistic flair, so hopefully Hello Fresh doesn’t mind.</p>

<hr />

<p>Recipe is for two, double everything for four, double again for eight, multiply by 3 for six, take the square root if you’re feeling irrational.</p>

<p>Recipe will successfully feed vegetarians.</p>

<h1 id="ingredients">Ingredients</h1>

<p>Hot tip: Prepare ingredients before cooking to give yourself the illusion that you’re saving time.</p>

<p>If you’re cooking immediately after ingredient prep; then pre-heat your oven to 200°C.</p>

<h2 id="breaded-cauliflower">Breaded cauliflower</h2>

<ol>
  <li>Cauliflower florets* (275g)</li>
  <li>Breadcrumbs (50g)</li>
  <li>Aioli (40g)</li>
  <li>Ketchup (12.5g)</li>
  <li>Chili flakes (a few pinches)</li>
  <li>Salt (a single, cheeky pinch)</li>
</ol>

<p>I recommend measuring the aioli and ketchup together (in a large bowl) as you’re going to be mixing them anyway.</p>

<p>* I’ve found that a half of a large cauliflower tends to be enough. The size of the florets is up to you, but it’s best to be on the side of larger florets. It’s 275g of florets, not the entire cauliflower.</p>

<h2 id="garlic-rice">Garlic rice</h2>

<ol>
  <li>Jasmin rice (150g)</li>
  <li>Garlic (2 cloves, crushed or chopped)</li>
  <li>Water (300ml)</li>
  <li>Butter</li>
  <li>Olive oil</li>
  <li>Salt (a single, cheeky pinch)</li>
</ol>

<p>Maybe also have another 100ml of water on hand separately. Just in case.</p>

<h2 id="bizarrely-delicious-mayonaise">Bizarrely delicious mayonaise</h2>

<p>Apparently this is called “Bang Bang Mayo”, but I guess you can name it whatever you’d like to impress your guests.</p>

<ol>
  <li>Mayonaise (25g)</li>
  <li>Soy sauce* (25ml)</li>
  <li>Ketchup (12.5g)</li>
  <li>Sesame seeds (10g)</li>
  <li>Chili flakes (like, six pinches maybe?)</li>
</ol>

<p>I also recommend measuring the mayonaise, soy sauce, ketchup, and sesame seeds together (in a small bowl) as you’re going to mix these together to make the bizarrely delicious mayonaise.</p>

<p>* Light or dark soy sauce, it’s your choice. I recommend dark.</p>

<h2 id="wok-vegetables">Wok vegetables</h2>

<p>If you don’t have a wok, then a small frying pan works fine.</p>

<ol>
  <li>Carrot, peeled &amp; chopped into half moons (1 medium sized stick)</li>
  <li>Spinach, roughly chopped up* (60g)</li>
  <li>The white parts of spring onions** (the type Hatsune Miku holds) (2 sticks)</li>
  <li>Olive oil</li>
</ol>

<p>Hot tip: Wash the spring onions as well as you can with cold water.</p>

<p>* If you can only find baby spinach, then grab that.  <br />
** Prepare these by chopping off the end at the root (the hairy part) and then peeling off a single layer of the onion. Also trim the green tips so they’re pretty. Chop these from the root towards the green tips, horizontally so you get nice circular discs of spring onion. The white parts fry up better, and we’ll save the green parts for garnish, so try to separate into a pile of white parts that look ideal for frying (I find it’s usually the bottom 75% of a stick).</p>

<h2 id="cucumber-salad">Cucumber salad</h2>

<p>These won’t be cooked, so make sure you wash the ingredients with cold water.</p>

<ol>
  <li>Cucumber chopped into circles (1 stick for two people)</li>
  <li>The green parts of spring onions* (2 sticks)</li>
</ol>

<p>If you’re not a cucumber type of person then a red pepper makes a good substitute. Half a red pepper cut into sticks.</p>

<p>* See above for prep guidance (I find it’s usually the top 25% of a stick).</p>

<h1 id="additional-equipment">Additional equipment</h1>

<ol>
  <li>Baking paper/parchment (1 sheet for a baking tray)</li>
</ol>

<h1 id="cooking">Cooking</h1>

<h2 id="the-krispig-blomkål">The krispig blomkål</h2>

<p>Pre-heat your oven to 200°C (if it already is pre-heated, then good job).</p>

<p>Mix the <strong>aioli</strong>, <strong>ketchup</strong> (12.5g), <strong>chili flakes</strong>, and <strong>salt</strong> in a large bowl - I find using a teaspoon to mix is effective, and you can use another teaspoon to scrape sauce off the one you used to mix. Make sure it is combined well.</p>

<p>We’ll be using this goo stuff to bread the cauliflower florets.</p>

<p>Add the <strong>cauliflower florets</strong> into the large bowl, and carefully mix with a non-metalic spoon (preferably plastic, but a wooden spoon works). Keep mixing until the sauce has practically disappeared from the bottom of the bowl.</p>

<p>Add the <strong>breadcrumbs</strong> a part at a time, mixing the cauliflower each time to get it all covered in breadcrumbs. Don’t worry if it’s not entirely covered, just makes sure you end up with all the breadcrumbs in the bowl, and a good amount on the cauliflower.</p>

<p>Line your baking tray with baking paper/parchment, and then evenly spread the breaded cauliflower florets over the paper’d tray. Ideally the florets will bake evenly.</p>

<p>Bake the breaded cauliflower in your preheated oven for 25 minutes (set a timer!).</p>

<p>When baked: Remove from oven. If you don’t have enough work space to remove it from the oven, then turn the oven off (but do not leave it in the cooling oven for more than 5 minutes!).</p>

<h2 id="the-garlic-rice">The garlic rice</h2>

<p>Melt a small chunk of <strong>butter</strong>, with a splash of <strong>olive oil</strong>, in a medium sized saucepan <strong>ON A LOW HEAT</strong>. If your butter turns brown (caramelises); you done goof’d.</p>

<p>Throw in your crushed/chopped <strong>garlic</strong>, and let it fry (still on low) for 1 minute 30 seconds. If your garlic turns black (burns); you done goof’d.</p>

<p>Immediately after the 1 minute 30 seconds throw in the <strong>rice</strong> and <strong>water</strong> (300ml) together, then add a pinch of salt. Whack that up to <em>full heat</em>, we’re going to bring it to a (very) brief boil.</p>

<p>When you see bubbles through the water, or hear the familiar sound of boiling, give the rice a brief stir with a non-metalic spoon (the sound of a metal spoon scraping on a saucepan… ugh), put a lid on the saucepan, and then turn the heat <em>back down</em> to medium*.</p>

<p>Cook on medium for 12 minutes (set a timer!), and <strong>do not open the lid</strong>.</p>

<p>When that timer goes off, step away from whatever you were doing (hopefully the next step of this recipe) and turn the heat to the <em>lowest</em> setting.</p>

<p>If you’re concerned about the rice, quickly take off the lid and give it a single stir to check that not all the water has boiled off. If it has: Add that emergency 100ml of cold water, and then immediately put the lid back on.</p>

<p>Cook on lowest for 10 minutes (set a timer!). The goal here is to steam the rice so it’s all fluffy.</p>

<p>When THAT timer goes off, take the rice off the heat entirely (move it to a cold part of the hob).</p>

<p>* If you don’t know what medium heat is on your hob, then go for a notch over the half-way point.</p>

<h2 id="the-bizarrely-delicious-mayonaise">The bizarrely delicious mayonaise</h2>

<p>In a small bowl, mix up the <strong>mayonaise</strong>, <strong>soy sauce</strong>, <strong>ketchup</strong>, <strong>sesame seeds</strong>, and <strong>chili flakes</strong>. Use a teaspoon for high precision mixing, and a second teaspoon to scrape the sauce off the first one.</p>

<p>That’s it. Put it to the side.</p>

<h2 id="wok-vegetables-1">Wok vegetables</h2>

<p>In a wok (or small frying pan), heat up a splash of <strong>olive oil</strong> (medium heat should be fine), and add in the half-moon’ed <strong>carrots</strong>. Carrots take a while to cook, so give it 5 minutes.</p>

<p>Add in the <strong>spinach</strong> and <strong>spring onion whites</strong> together, and cook for another 5 minutes.</p>

<h1 id="serving">Serving</h1>

<p>Get your bowls.</p>

<p>The water should be boiled off from the rice, so if you’re British you can put down that sieve, and instead grab a spoon suitable for scooping out rice (a deep plastic one, or a wooden rice spoon if you’re posh).</p>

<p>Divide the rice into the bottom of each bowl.</p>

<p>Divide the breaded cauliflower into each bowl (on top of the rice).</p>

<p>Divide the wok vegetables into each bowl (to one side, if you want a nice presentation).</p>

<p>On the side of the bowl without the wok vegetables, put the <strong>cucumber</strong> slices (you can make them lean on each other for a nice presentation).</p>

<p>Pour over the bizarrely delicious mayonaise in a nice zig-zag pattern. You want to get a nice splash on the wok vegetables, cucumber slices, and the breaded cauliflower. Make sure you divide this equally between the bowls, don’t dump it all on the first bowl…</p>

<p>Sprinkle over the <strong>spring onion greens</strong> as a garnish.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/blomkal/blomkal.jpg" alt="The final Krispig Blomkål" width="600" /><br />
</p>

<p>If the bizarrely delicious mayonaise isn’t enough for you, then siracha mayo goes quite well with this dish also.</p>

<h1 id="drinks-to-pair-with">Drinks to pair with</h1>

<p>Lager beers go well with this (pilsners, etc), but a pale ale works too (IPA).</p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[A recipe for crispy cauliflower.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://felixjones.co.uk/assets/blomkal/thumb.jpg" /><media:content medium="image" url="https://felixjones.co.uk/assets/blomkal/thumb.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">What does Felix do at Mojang?</title><link href="https://felixjones.co.uk/2022/11/17/what-do-i-do.html" rel="alternate" type="text/html" title="What does Felix do at Mojang?" /><published>2022-11-17T00:00:00+00:00</published><updated>2022-11-17T00:00:00+00:00</updated><id>https://felixjones.co.uk/2022/11/17/what-do-i-do</id><content type="html" xml:base="https://felixjones.co.uk/2022/11/17/what-do-i-do.html"><![CDATA[<p>I notice that content creators are somewhat forced to make guesses as to what the job titles &amp; responsibilites are for various Mojang employees, and that’s probably because we don’t really show much of what goes on in the day-to-day for a Minecraft dev.</p>

<p>It is probably easier for us to individually talk about our own jobs, and my job is actually something I talk about a lot when I give talks to universities about working in the games industry.</p>

<p>As usual: All my opinions expressed here are my own, they are not representative of Mojang Studios, nor the Minecraft team. I’m just Felix the game developer talking about his job.</p>

<hr />

<h1 id="my-job-title">My Job Title</h1>

<p>Probably the most official <em>public</em> title would be the game credits itself, where I am under the “Game Developer” heading:</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/minecraft/credits.png" alt="My name in the Minecraft 1.19.2 credits" width="600" /><br />
</p>

<p>Someone even made an empty <a href="https://www.mobygames.com/developer/sheet/view/developerId,1165026/">Moby Games</a> page for my Minecraft credit!</p>

<h2 id="a-youtube-job-title">A YouTube job title!?</h2>

<p>Whenever I’ve been involved in videos on the Minecraft YouTube channel someone from the production team will send me a message asking what job title should go on under my name.</p>

<p>Let’s take a trip down memory lane of my Minecraft YouTube appearances.</p>

<p align="center">
<a href="https://www.youtube.com/watch?v=BPJOs8nFMv0"><img src="https://felixjones.co.uk/assets/minecraft/dev_diary.jpg" alt="My Nether update dev-diary appearance" width="600" /></a><br />
</p>

<p>Holy heck just noticed my Twitter handle is in this appearance, pretty sure I could have used that as evidence criteria for getting verified on Twitter (back when being verified actually had meaning).</p>

<p>Fun fact about this video: We were all working from home, and I happened to be trapped in the UK during the first of the pandemic lock-downs. Behind me on that white wall were studs used for hanging pictures; I had to keep my head and my hands as much out of the way of those studs so they could be digitally removed in post.</p>

<p align="center">
<a href="https://www.youtube.com/watch?v=hwVpTyAGaiA"><img src="https://felixjones.co.uk/assets/minecraft/ask_moj.jpg" alt="My first Ask Mojang appearance" width="600" /></a><br />
My "children's TV entertainer" costume.
</p>

<p>My favourite part of this video is when I preemptively clap and smile at Paulo’s suggestion of adding beans, because it was the 2nd take of him saying that so I knew exactly what was coming up. It either delivered as some kind of crazy awesome synergy between us, or me just being far too enthusiastic about being on camera.</p>

<p align="center">
<a href="https://www.youtube.com/watch?v=pH_6-ZVOUAk"><img src="https://felixjones.co.uk/assets/minecraft/ask_moj_cac.jpg" alt="My second Ask Mojang appearance" width="600" /></a><br />
This is me counting how many diamonds I mined since Caves &amp; Cliffs Part 2.
</p>

<p>In this video I begin my answer with an excellent joke that I had originally said prior to the shoot, so I decided to repeat it again on camera—and everyone put on a convincing laugh as if it was the first time they heard the joke.</p>

<p>That was the moment I realised just how good my colleagues are in front of the camera, it’s probably a skill we take for granted. I was very impressed, and I still think about that moment.</p>

<h1 id="what-job-did-i-sign-up-for">What job did I sign up for?</h1>

<p>On my contract I am a “Java Game Developer”, so that’s probably why I gave that as my job title for the YouTube videos above.</p>

<p>Actually now that I’m looking at my contract again, there’s two responsibilities written on it that I will paraphrase (I won’t show my actual contract):</p>

<ul>
  <li>Design and implement gameplay systems</li>
  <li>Improve stability and performance</li>
</ul>

<p>So I guess that’s what I do at Mojang? These are actually more vague than one might think; generally any game developer is expected to implement “systems” (gameplay, or otherwise), is expected to fix bugs (make the game more stable), and the word “performance” can be interpreted to mean many, many more things than just <em>frames per second</em>.</p>

<h1 id="what-i-actually-do-at-mojang-studios">What I <em>actually</em> do at Mojang Studios</h1>

<p>As of this writing, my official responsibilities are all Minecraft Java Edition—which basically means “stuff” that is specific to Java Edition, and has little-to-no relevance to Bedrock Edition (so not the gameplay update content stuff, more Java Edition engine things and features).</p>

<p>That being said, I’ve noticed that many of us on the Minecraft team have many more responsibilities than you’d typically expect from a game developer. <a href="https://felixjones.co.uk/2022/10/16/mob-vote.html#modders-probably-arent-working-in-an-organisational-structure">I even mentioned it here</a>.</p>

<p>What surprises my friends and family when I tell them about my job is how close to the community we are. They are surprised at the level of interaction I have, and seem to view me as doing the job of marketing.</p>

<p>Our personal social media accounts are definitely <strong>not</strong> Minecraft marketing. To be honest, I actually use my twitter to generate Minecraft news for ItzJhief, and come up with new Minecraft jokes for Phoenix SC to steal <img style="vertical-align:middle;" src="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/twitter/322/man-technologist_1f468-200d-1f4bb.png" height="16pt" /></p>

<p align="center">
<img src="https://felixjones.co.uk/assets/minecraft/salaries.jpg" alt="Mimic a fraction of our power meme, but it is about game developers having small salaries." width="600" /><br />
</p>

<h2 id="the-one-responsibility-that-surprises-people-the-most">The one responsibility that surprises people the most</h2>

<p>From my experience; the most common thing that surprises Minecraft fans is that Java developers themselves write the snapshot posts and changelogs.</p>

<p>I remember a new hire being surprised by this, and I think I remember <a href="https://www.youtube.com/channel/UC_GQ4mac4oN3wl1UdbFuTEA">IBXToyCat</a> being surprised by this during conversation over lunch that one time 🤔</p>

<p>We have a writing team and a community team that gets involved and helps out, but when it comes to technical stuff the best people to write it are probably the developers themselves.</p>

<p>The team also produces the screenshots for the blog posts, which can sometimes turn into a <a href="https://twitter.com/Xilefian/status/1397913052545052672?s=20&amp;t=SByqb3tYqyk4io6z6I4umA">competition of who can create the best screenshot</a>.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/minecraft/1191rc2.webp" alt="Screenshot of a Minecraft farm with a pig and a warden" width="600" /><br />
</p>

<p>I’m actually quite proud of some of our blog-post screenshots. <a href="https://twitter.com/gegy1000">Gegy</a> and I worked on this one, which involved some command trickery in multiplayer. I’m pretty fond of the “Minecraft animal staring back at you” vibe we got going on here.</p>

<h2 id="dont-blame-xilefian-he-isnt-responsible-for-this">“Don’t blame Xilefian, he isn’t responsible for this”</h2>

<p>I once saw a comment like this in a thread regarding something that was broken in a snapshot, which made me laugh because I was actually responsible for the thing.</p>

<p>It is impossible for players to know what part of the game they can attribute to who, and IMO that’s probably a good thing as the responsibility of the game should be shared across all Minecraft developers.</p>

<p>That being said, there are some things in the game that when I look at I think “That is soooo <a href="https://twitter.com/Cojomax99">Cory</a>”, and checking the code I will see Cory’s fingerprints all over the history.</p>

<p>I do find YouTube videos that attribute the entirety of a Minecraft update to the beloved Minecraft modder: <a href="https://twitter.com/kingbdogz">kingbdogz</a>.</p>

<p>It could be an interesting thought experiment to try and figure out what a Minecraft update would look like if it was indeed dictated by a single designer.</p>

<h1 id="my-next-job-title">My Next Job Title</h1>

<p>Someone thought it would be a good idea to make me even more responsible for <em>the best selling video game</em> than I already am, so starting early December my job title will no longer be “Java Game Developer”.</p>

<p>I’ll probably write another post revealing what my next Minecraft job title is when the time comes (there’s a few funny stories related to that).</p>

<hr />

<p>This was a bit of a random post, but the job titles we have is something I think about a lot when it comes to community interactions, and with my job title changing soon it has been on my mind a fair bit.</p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[Even some of my colleagues have no idea what I do]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://felixjones.co.uk/assets/minecraft/thumb.png" /><media:content medium="image" url="https://felixjones.co.uk/assets/minecraft/thumb.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Website Update: Now you can leave a Comment</title><link href="https://felixjones.co.uk/2022/11/05/giscus.html" rel="alternate" type="text/html" title="Website Update: Now you can leave a Comment" /><published>2022-11-05T00:00:00+00:00</published><updated>2022-11-05T00:00:00+00:00</updated><id>https://felixjones.co.uk/2022/11/05/giscus</id><content type="html" xml:base="https://felixjones.co.uk/2022/11/05/giscus.html"><![CDATA[<p>With the future of Twitter in uncertain hands I decided I should probably have a back-up plan for discussions around my website content.</p>

<hr />

<p>I mentioned back in July 2022 that I’d enable Discus comments where it made sense, but with Discus being rather evil I instead started telling people to @ me on Twitter (<a href="https://www.twitter.com/Xilefian">@Xilefian</a>) with their thoughts.</p>

<p>For myself, Twitter is great for visibility. Even before I had the <em>fantastically cool</em> clout of Minecraft-dev, my Twitter sphere was quite healthy in the communities around graphics programming and game development.</p>

<p>For the lucky few like myself, Twitter has been invaluable for learning and communicating. Thanks Twitter.</p>

<h1 id="whats-next-after-twitter">What’s next after Twitter?</h1>

<p>If Twitter had a mass-exodus (digg style) I wouldn’t be surprised if those who have the priviledge of high twitter-visibility go back to individual blogs with RSS.</p>

<p>This somewhat goes back to the days of Web 1.0 where everyone had a personal website.</p>

<h2 id="mastodon-looks-interesting">Mastodon looks interesting</h2>

<p>So Twitter is kind of about you just blasting out whatever personal crap you have going on, whereas Mastodon’s servers promote a most focused blasting out of very-specific crap that you have going on.</p>

<p>If you want the personal blog style, you need to run your own server, or start spewing all over someone else’s server that was set up for twitter-style top-of-mind discussions.</p>

<p>So perhaps the form I imagine of “individual blogs with RSS” is individual Mastodon servers. There’s a technical barrier that’s probably greater than just rolling your own website (which is already a high technical barrier).</p>

<h2 id="using-github-lol-as-a-social-platform">Using GitHub (lol?) as a social platform</h2>

<p>The other day I had a chat with <a href="https://twitter.com/wChiwi">Chi</a> regarding the Twitter “news” and I mentioned that I am considering looking into using GitHub as a sort of stupid twitter-clone - and that idea actually stuck with me.</p>

<p>In terms of visibility, I think I’m doing pretty well on GitHub: As of this writing I have 209 followers on GitHub (<a href="https://github.com/felixjones">give me a follow</a>).</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/giscus/1followerongithub.jpg" alt="100 twitter followers &lt; 5 reddit followers &lt; 1 follower on github" width="600" /><br />
</p>

<p>The more I think about it, the more it makes sense to use GitHub for topic-based social discussion (as long as your topic is related to software development). My second biggest crowd after Minecraft is probably the game development scene, so why not use GitHub.</p>

<p>It would be interesting if GitHub set up a feed where you can see the top-of mind from individuals that you follow. Perhaps this already exists? Right now I just see a feed of all their boring, normal software development activity (make a repo, push a commit, merge a PR, etc).</p>

<h1 id="giscus-blog-commenting">Giscus blog commenting</h1>

<p>This morning when I was making my coffee I was reading about all the Twitter employees who were unfortunately fired in the wake of the “news” and it got me thinking even more about my GitHub social discussion idea.</p>

<p>I decided I’d spend this weekend building a sort of comment system using GitHub discussions, so I booted up my development machine and began the way all good software starts: by google’ing for whatever already exists.</p>

<p>Even with my garbage tier search terms I immediately found that someone had already done what I had planned and it is quite glorious: <a href="https://giscus.app/">giscus</a>.</p>

<p>The name alone communicated that it was what I wanted for replacing discus on this site, and setting up giscus was ridiculously easy: it worked first time.</p>

<p>So I went ahead and enabled it on every page. I hope you have a GitHub account.</p>

<h1 id="whats-next-for-the-site">What’s next for the site?</h1>

<p>I am thinking of experimenting with some kind of top-of-mind style tweet-esque thing on the homepage of this site, so my personal top-of-mind stuff would be visible for discussion, and I can share cool games, projects, communities, political thoughts, and more.</p>

<p>But for now, Twitter is still here, so I’m sticking to Twitter for that kind of thing. This blog will do for continuing my long-form content, and the comment box will do for continuing discussion in a place that isn’t dependant on the existance of Twitter (but instead dependant on Microsoft’s seemingly infinite free storage on GitHub).</p>

<p>I should probably set up RSS.</p>

<h2 id="when-will-you-add-dark-mode">When will you add dark-mode!?</h2>

<p>Yeah I need to do this at some point. I’ll look into it when I got some time, but I need to read up if there’s any data laws I need to keep in mind when I write a boolean flag to your disk for if you have dark mode turned on/off. Perhaps there’s an OS/browser setting I can use?</p>

<h1 id="leave-a-comment">Leave a comment!</h1>

<p>Below here should be the new comment section. I’ve even left GitHub reactions enabled so you can drop an emoji that best describes your emotional state when reading the crap I write.</p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[With the future of Twitter in uncertain hands I decided I should probably have a back-up plan for discussions around my website content.]]></summary></entry><entry><title type="html">Mob Vote post-mortem</title><link href="https://felixjones.co.uk/2022/10/16/mob-vote.html" rel="alternate" type="text/html" title="Mob Vote post-mortem" /><published>2022-10-16T00:00:00+00:00</published><updated>2022-10-16T00:00:00+00:00</updated><id>https://felixjones.co.uk/2022/10/16/mob-vote</id><content type="html" xml:base="https://felixjones.co.uk/2022/10/16/mob-vote.html"><![CDATA[<p>First of all: All my opinions expressed here are my own, they are not representative of Mojang Studios, nor the Minecraft team. It’s just a small sliver of my thoughts (my colleagues certainly hear the meat of what I have to say).</p>

<p>To prove this isn’t representative of the Minecraft team, I (Xilefian) will type the F-word: Fuck. Mojang Studios would never write that in any official statement, so you’d better believe it’s just Felix’s conversational ramblings.</p>

<p>My colleagues have suffered through the full wrath of my feedback, this post is just a small taste of what they get to hear from me.</p>

<p>For purposes of full transparency: I do not have any direct involvement in Minecraft Live, nor the mob votes, so I am likely talking out of ignorance regarding how things work and my opinions are probably going to be garbage as a result of that ¯\_(ツ)_/¯</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/mobvote/sniffer.webp" alt="The Minecraft Sniffer won the vote." width="600" /><br />
</p>

<p>Every year for Minecraft Live there is the Mob Vote, where the community votes for a mob to be added to the next Minecraft update from three candidate mobs.</p>

<h1 id="minecraft-live-2020">Minecraft Live 2020</h1>

<p>The mob vote for Minecraft Live 2020 was between three mobs: Iceologer, Moobloom, and Glow Squid.</p>

<p>The favourite amongst the technical Minecraft community was the Iceologer, and quite frankly I expected the Iceologer to win because the technical Minecraft agreed that it was the obvious choice, and their audience agreed and carried this wisdom onwards when campaigning for their mob vote favourite.</p>

<p>Meanwhile, a rather famous Minecraft content creator made a joke tweet stating that they will follow (on twitter) everyone who can prove they voted for the Glow Squid - providing some incentive for their many, many fans to vote for their favourite mob. They did retract this offer, but many see this as the damage being already done. The Glow Squid won.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/mobvote/glowsquid-minecraft.jpg" alt="The Minecraft Glow Squid won the vote." width="600" /><br />
</p>

<h2 id="was-the-vote-really-rigged">Was the vote really rigged?</h2>

<p>The Glow Squid win was a real bloody surprise to myself, as well as the technical Minecraft community. The sentiment within my circles was that it was a meme vote, and undeserving of its victory.</p>

<p>Immediately I will say: I do not believe that any single creator swung the 2020 mob vote. I had this opinion at the time, and I still hold that opinion.</p>

<p>The first thing I did was ask my younger niece and nephew which mob did they vote for. They both said “The Glow Squid, of course” (as if it was the obvious choice). These are young Minecraft fans who had no idea who the content creator that “rigged the vote” was. I then started looking at what parents were saying about which mob their child picked, and again I was seeing a lot of support for the Glow Squid.</p>

<p>So I am convinced that what happened was our familiar Minecraft content communities created a conversation bubble where they put forward some indepth thought and discussion regarding why the Iceologer was a good idea, their audience heard these good thoughts and discussions, agreed, and then spread the converstaion as far as the familiar Minecraft content communities could reach.</p>

<p>But these communities probably don’t have the reach that we imagine. They probably aren’t in the school playgrounds where many Minecraft discussions are taking place.</p>

<h3 id="but-minecraft-isnt-just-played-by-kids">But Minecraft isn’t just played by kids</h3>

<p>Yes, Minecraft is played by everyone, including adults. Adults who may not have the time to keep up with Minecraft news, who may not be able to take time out of their day to vote for a Minecraft mob, or time to read up about any of the Minecraft Live news.</p>

<p>After every Minecraft Live I check the conversation on Reddit, and I see the same pattern: A discussion about an announced feature, with many people in the comments saying “what is this?” and “was there some kind of announcement?”. I imagine that’s the normal Minecraft player: They have no idea a mob vote is even happening.</p>

<h2 id="why-the-glow-squid">Why the Glow Squid?</h2>

<p>This is very anecdotal, but when I looked into why indiviudals wanted the Glow Squid I did indeed see comments about how the submarine in the video was cool (the submarine was not added to Minecraft, and was never a planned idea), and also comments about how the Glow Squid will hypnotise players like in the video (the Glow Squid does not hypnotise players, and I have personally never seen plans to make the Glow Squid hypnotise players).</p>

<p>I didn’t see many comments expecting the Glow Squid to act as a dynamic light, and I imagine this is because dynamic lighting isn’t a concept well understood by the kids who were so interested in the Glow Squid. Of note, I noticed the frustrations from the community were pivoted around “it doesn’t even glow!” - a sentence which has stuck with me.</p>

<p>I passed this feedback to the team as a lesson to learn: There is a balance to be had between the media team exercising their creativity (which I 200% believe is something we should promote), and presenting good, correct information to the community.</p>

<h1 id="minecraft-live-2021">Minecraft Live 2021</h1>

<p>To me, 2021 felt far less chaotic and drama-filled than 2020 (or perhaps I hang out in the wrong places?). The Allay won the vote, beat the Glare and the Copper Golem.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/mobvote/allay.webp" alt="The Minecraft Allay won the vote." width="600" /><br />
</p>

<p>I had wanted the Copper Golem to win, I personally find Minecraft builds most charming when there’s a bit of life and activity to them (I tend to construct useless piston and light contraptions behind the windows of my building façades, so it would look like someone was at home in them).</p>

<h2 id="the-mob-presentations-were-unbalanced">The mob presentations were unbalanced</h2>

<p>When watching the mob videos, the utility of the mobs was boiled down to:</p>

<ul>
  <li>Thing that tells you where it’s dark (Glare)</li>
  <li>Thing that pushes buttons, and then freezes still (Copper Golem)</li>
  <li>Thing that you give an item for it to find, which will then pick up the same item from the ground when encountering said item, and it will then drop those items at a note block (Allay)</li>
</ul>

<p align="center">
<a href="https://www.youtube.com/watch?v=XdxGwg7cgjw"><img src="https://img.youtube.com/vi/XdxGwg7cgjw/0.jpg" alt="The Minecraft Allay vote video." width="600" /></a><br />
</p>

<p>I’m probably being a bit harsh, but to me you can tell that the <a href="https://www.youtube.com/watch?v=IXu7yKUmBEw">Allay was a mob that had already been quite fleshed out and developed versus the other two</a>.</p>

<p>Anyhow, the technical Minecraft community saw the utility in the Allay, so the discussion around the Allay winning was mostly positive.</p>

<p>I remember sarcastically presenting the 3 options to my colleagues in the office after the vote, where I went into grand detail about all the possibilities of the Allay versus the other two. I think there was a lesson to be learned, but I was too upset about the Copper Golem losing to communicate it properly at the time.</p>

<h2 id="briefly-why-i-liked-the-copper-golem">Briefly: Why I liked the Copper Golem</h2>

<p>I remember when I was testing the performance of the Fabulous graphics shaders on Java Edition I downloaded some futuristic city maps, and these amazing cities all felt like some kind of 28 Days Later apocolypse had occurred because they were so spookily empty. That was still fresh in my mind when I decided the Copper Golem was my choice.</p>

<p>It’s a shame that we communicated the Copper Golem’s primary function as being a button-pushing drone. In my imagination I foresaw us one day expanding the Copper Golem functions to further promote the feeling of a base being alive.</p>

<h1 id="minecraft-live-2022">Minecraft Live 2022</h1>

<p>This year the mob vote was done differently, and Minecraft Live was prefaced <a href="https://www.minecraft.net/en-us/article/featuring-features-from-now-on">with a blog post</a> that this year the team will only show off things that are “ready to take the stage”, this meant that the team would only reveal features that are ready for players themselves to try out.</p>

<p>The mob vote, by its nature, can’t follow that rule. If the mobs were developed to a stage where players could try them out, then there wouldn’t be a mob vote and all three mobs would be in the game (and we’d be missing two other features that otherwise would have been in the update).</p>

<h2 id="the-mob-presentations-were-unbalanced-again">The mob presentations were unbalanced again</h2>

<p>I would have originally said the lesson to learn from 2021 was not make one mob clearly more awesome than the other, but after this year I’d revise it to: don’t pack one mob with more information than any other.</p>

<ul>
  <li>Thing that hides in caves and gives you loot when found (Rascal)</li>
  <li>Thing that holds items and walks back to where you placed it (Tuff Golem)</li>
  <li>Thing that has ancient mystery, hatched from ancient eggs that can be found underwater, can be bred to revive the ancient lost mob, sniffs out plants to dig up ancient seeds, ancient seeds that you can grow into a new plant, and it can also grow to be really big (The Sniffer)</li>
</ul>

<p align="center">
<a href="https://www.youtube.com/watch?v=MPJ2dzVcOgg"><img src="https://img.youtube.com/vi/MPJ2dzVcOgg/0.jpg" alt="The Minecraft Sniffer vote video." width="600" /></a><br />
</p>

<p>Again, I’m probably being a bit harsh (<a href="https://twitter.com/Xilefian/status/1581217769827504128?s=20&amp;t=UW8aNw4NmncLLd4hD48UFg">because I wanted the Rascal to win</a>), but I was already bracing for a Sniffer victory once all three videos were released because it felt like another case of one obvious mob.</p>

<blockquote class="twitter-tweet" data-conversation="none"><p lang="en" dir="ltr">The sniffer received more than half of your votes! 🤯<br /><br />Mob Vote 2022 results: <br />Sniffer - 55.1%<br />Rascal - 27.7%<br />Tuff golem - 17.2%<a href="https://twitter.com/hashtag/MinecraftLive?src=hash&amp;ref_src=twsrc%5Etfw">#MinecraftLive</a></p>&mdash; Minecraft (@Minecraft) <a href="https://twitter.com/Minecraft/status/1581377147838439424?ref_src=twsrc%5Etfw">October 15, 2022</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<h2 id="it-was-all-in-the-details">It was all in the details!</h2>

<p>One frustration I saw repeated was that details for the Tuff Golem and Rascal were hidden on the blog posts on the websites, which are an extra click away from the easy-to-consume videos, and many Tuff Golem voters specifically wrote to me saying “I wasn’t going to vote Tuff Golem until I read the blog post”.</p>

<h1 id="why-have-mob-votes-to-begin-with">Why have mob votes to begin with?</h1>

<p>When I first joined Mojang back in 2020 this question was raised before Minecraft Live, and the answer I heard was quite wonderful. I can’t quote it exactly, but the gist was: It is a way for us to have all Minecraft players have a say in the game’s development, not just the players who we interact with every day in the community.</p>

<p>I really like that, it plays into my discovery about the Glow Squid being a favourite amongst the Minecraft community we don’t have much visibility over (the Minecraft communities that occur in a school playground), and I definitely believe the mob votes give us more than it does take us away (for one, it’s an anticipated part of Minecraft Live itself, and thus draws a big crowd).</p>

<h1 id="why-not-add-all-three-mobs">Why not add all three mobs?</h1>

<p>I was surprised by this idea being repeated in the community, because I had thought (from my priviledged position) that the answer would have been obvious.</p>

<p>Ignoring the fact that this removes the mob vote itself (which would be a shame), adding all three mobs is in effect adding none of the mobs, because they would be folded into the regular update features and would disappear from the community. It would probably no longer even be a mob, it would just be another slot for another feature, be it a block, biome, item, mob, whatever. And given that time isn’t infinite, the three mobs would be cut back down to one mob anyway.</p>

<p>If we had the bandwidth to add all three mobs, that bandwidth is already being used for other parts of the update.</p>

<h2 id="but-seeing-the-other-two-mobs-lose-makes-me-upset">But seeing the other two mobs lose makes me upset</h2>

<p>I did see an interesting comment on this, where a player was specifically upset because we have shown them mobs that they want in the game, but they won’t be in the game. This was the elusive “Mojang promised us XYZ” sentiment that I had been looking for, finally found it in 2022: this was a player who sees any Minecraft content at all to be a promise, and the mob vote to them was a vote for which two promises will we break. Very interesting, and I’m not sure how to navigate that one.</p>

<p>The first thing that came to my mind was “wow buddy, you’d hate to spend a day at Mojang”. We discuss ideas constantly, just walking through the hallway, whilst grabbing a coffee, when trying to put out fires that we accidentally caused in the microwave, during all these normal office moments we talk about ideas. Sometimes it’s mob ideas that we experimented with years ago, sometimes it’s new ideas, sometimes it’s ideas that were cut, sometimes it’s future ideas that we aren’t sure will make it.</p>

<p>If all of those ideas were promises being broken, then this individual would have a horrible time just watching their favourite game be developed. To me, the mob vote is voting for one of those ideas to not be trapped as a lost echo in the hallways of Mojang Studios.</p>

<p>I’m probably not communicating my point here very well, probably because I need more time to think on it.</p>

<h2 id="but-modders-can-add-these-mobs-real-fast">But modders can add these mobs real fast</h2>

<p>I almost forgot to address this, but I really should.</p>

<p>Modders have a few benefits on their side:</p>

<h3 id="the-mobs-have-already-been-designed">The mobs have already been designed</h3>

<p>A lot of the work done is in the design phase, once that’s done developers then start picking up tasks that are needed in terms of priority.</p>

<p>Modders can skip the design phase (because we already did it), don’t need to worry about the current work priority (because they don’t work at Mojang) and can get on with it on their own time.</p>

<h3 id="modders-only-work-in-java-edition">Modders only work in Java Edition</h3>

<p>I’m not sure the community can really understand how much working on two different games with the goal of feature parity slows things down. A Java technique almost never translates into something usable in Bedrock.</p>

<p>Quite frequently we hit into problems where we’ve ran ahead with a solution in Java Edition (where we pretend we have infinite memory), only to be hit by the realities of needing to get the idea working on platforms without infinite memory for Bedrock.</p>

<p>Modders are incredibly lucky that they just need to worry about Java Edition.</p>

<h3 id="modders-probably-arent-working-in-an-organisational-structure">Modders probably aren’t working in an organisational structure</h3>

<p>It’s not just working on the game, it’s working on the franchise. Minecraft has a LOT going on outside of just features in the game, and employees at Mojang Studios are uniquely responsible for quite a lot of stuff that would shock and surprise anyone expecting a typical software/game company setup.</p>

<p>Part of that structure includes communication through code. There are a LOT of people touching the code at the same time, modders tend to be working on a codebase that’s set at a particular level of Minecraft (almost never a latest snapshot) and probably don’t have a pull-request workflow that has 20+ people staring at it.</p>

<h3 id="mods-dont-need-to-get-it-right-the-first-time">Mods don’t need to get it right the first time</h3>

<p>I have noticed that many mods showcased for impressive speed of development versus Mojang have the label “beta” on them. A modder can release a mod, and then work on the bugs and fixes for post-release patches.</p>

<p>Of course, we fix bugs post-release, but these slow down development of other features that need priority, so it’s better to get it right the first time, and that takes time.</p>

<h3 id="modders-have-an-incentive-to-make-the-mob-vote-mods-first">Modders have an incentive to make the mob vote mods first</h3>

<p>Adding them as fast as possible before anyone else (including Mojang) is a good way to get downloads of your mod (or get players to join your server where you host these mods).</p>

<p>This is why the modding community is so great, it drives itself to innovate at a pace that cannot be matched by a slow organisation. Incentives like “we did it before Mojang” promotes modding and is fantastic.</p>

<p>Around the time of the mob votes, I see so much community activity around player created content, including mods.</p>

<h1 id="how-to-fix-the-mob-vote-by-felix">How to fix the mob vote: By Felix</h1>

<p>Again, this is my personal opinion, and when I presented this to some of my colleagues they were quite shocked, confused, and frightened, because this idea is a little crazy.</p>

<p>My crazy idea would be to say practically nothing about the mobs. We show off their design, we show off the environment it is in, and we say if it is a passive mob or a hostile mob, and that’s it. The players then vote on the mob that gives them the best vibes.</p>

<p>We then go into round 2 of voting: What should this mob do? Does it drop a rare item? Does it give a new block? Can you ride it?</p>

<p>And then we go into the final round of voting: What should the mob be called?</p>

<p>It’s an extreme, complex, and cumbersome approach, but I think this would end any kind of appearance of imbalance where one mob is an obvious vote versus the others.</p>

<p>My favourite part of this is that it moves the design ambiguity back towards our game designers, who would now be given far more room to flesh out the mob after the fact of the vote (instead of revealing all our cards at the beginning).</p>

<p>I will flesh out this idea a bit more to try and find the flaws in it - and more importantly figure out if it is solving anything worth while, because another thing I realised:</p>

<h1 id="the-mob-vote-is-fine">The Mob vote is fine</h1>

<p>Yeah after Minecraft Live 2022, I kind of felt like I didn’t need to write this huge post. The mob vote is actually fine, it’s harmless, it’s just a game, and it’s a game that will go on for a long time, any mistakes made can be fixed in an update.</p>

<p>So perhaps we don’t need to fix or change anything.</p>

<p align="center">
<img src="https://felixjones.co.uk/assets/mobvote/FbBqxVeXoAAoMKt.jpeg" alt="Photo of me trying to play Minecraft on the eggs-box." width="600" /><br />
</p>

<p>That’s 2% of my thoughts on mob votes. If you want the other 98%, then you need to join Mojang, get your NDA signed, and ask me in person.</p>

<p>If you disagree with me: <a href="https://twitter.com/Xilefian">then @ me on twitter</a>. Opinions are welcome and I tend to forward interesting points to the rest of the Minecraft team.</p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[My thoughts about the Minecraft mob vote]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://felixjones.co.uk/assets/mobvote/roundup.webp" /><media:content medium="image" url="https://felixjones.co.uk/assets/mobvote/roundup.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Resident Evil’s tank controls are good</title><link href="https://felixjones.co.uk/2022/09/22/tank-controls.html" rel="alternate" type="text/html" title="Resident Evil’s tank controls are good" /><published>2022-09-22T00:00:00+00:00</published><updated>2022-09-22T00:00:00+00:00</updated><id>https://felixjones.co.uk/2022/09/22/tank-controls</id><content type="html" xml:base="https://felixjones.co.uk/2022/09/22/tank-controls.html"><![CDATA[<p>I am once again here to make the case that the thing everyone says is bad, is actually good.</p>

<p><img src="https://felixjones.co.uk/assets/resi/bite.webp" alt="Screenshot of Resident Evil. A zombie is biting Jill." width="600" /><br /></p>

<h1 id="the-problem">The problem.</h1>

<p>Take a look at the original PlayStation controller:</p>

<p><img src="https://felixjones.co.uk/assets/resi/PSX-Original-Controller.jpeg" alt="The PSX Gamepad" width="400" /><br />
(Image by the awesome <a href="https://commons.wikimedia.org/wiki/User:Evan-Amos">Evan Amos</a>)</p>

<p>Notice that this controller does not have analogue inputs. The player is forced to move only in the 8 directions allowed by the directional-pad on the left.</p>

<p>How does the player move at angles between those 8 directions? Tank controls to the rescue: By instead using left/right buttons to spin the player, the player can now walk forwards/backwards at all those angles within the 8 directions.</p>

<h1 id="the-other-problem">The other problem.</h1>

<p>The Resident Evil HD Remaster has an option to remove tank controls, in favour of the finer analogue input that can reach all those angles between the 8-directions. This is great for the modern gamer, who is trained to expect “up” to mean “somewhere in the direction towards the top of the screen”, but it immediately exposed the 2nd problem that tank controls solved.</p>

<p>Resident Evil has multiple fixed camera angles of the same room, and as the player reaches the edge of one angle the other camera angle is swapped in.</p>

<p>If you were holding “left” to run towards the “left” edge of the screen, but the new camera angle swaps to the other side of the player, then within the world the “left” edge of the screen is now on the “right”, so if you were still holding “left” you’d now be walking the other direction, <strong>back towards the edge of the screen you came from</strong>. This results in the player accidentally flipping between two screens if they weren’t quick enough to release the movement button.</p>

<h2 id="the-final-fantasy-solution">The Final Fantasy solution</h2>

<p>The PSX era Final Fantasy games (which also use fixed camera angles in a 3D world) solves this by:</p>

<ol>
  <li>Making the location the player loads into be a little ways away from the edge of the screen</li>
  <li>Having larger screens that pan, instead of changing camera angle, requiring a loading screen between areas</li>
</ol>

<p>Both of these give the player plenty of time to let go of the movement key and re-orient themselves.</p>

<h2 id="the-resident-evil-hd-remaster-solution">The Resident Evil HD Remaster solution</h2>

<p>When you use the option to remove tank controls, the HD Remaster will detect when the player is holding the analogue stick between camera angle changes, if this is the case then on the new camera angle instead of resetting where “up” means relative to the new camera angle, the previous camera angle’s “up” is kept relative to the world.</p>

<p>I’ll try to explain that better: When you press “up” you define a new “north” within the world, this “north” is kept between camera angle changes until you let go of the analogue stick.</p>

<h1 id="okay-so-tank-controls-were-necessary-but-they-still-suck">Okay so tank controls were necessary, but they still suck</h1>

<p>No.</p>

<p>I see a few comments every now and then from players who say the tank controls added tension to the horror. I do think they are assigning too much design thought behind the tank controls (IMO they are the solution for fine movement with digital inputs), but I do get what they’re saying, it was an emergent part of the Resident Evil experience, attempting to back up from a zombie that got too close, only to trigger a jump scare behind you that you now need to sprint forward to avoid, running around the first zombie.</p>

<p>This is probably felt best in Resident Evil 4, which is a third-person “over the shoulder” game. It was the last Resident Evil game before Capcom went down the weird path of making them action games. I feel the availability of strafing is what contributed to the move away from survival horror, and towards action games.</p>

<p>With that player sentiment towards tank controls, I feel there is something to tank controls that’s worth looking into.</p>

<h1 id="other-games-with-tank-controls">Other games with tank controls</h1>

<p>Indeed, there are games that have tank controls that people seem to forget. The id games Wolfenstein 3D, Doom, and Quake use tank controls, with the modifier key to convert the turn directions to strafe directions. I wouldn’t be surprised if the id game <a href="https://en.wikipedia.org/wiki/Hovertank_3D">Hovertank 3D</a> used tank controls because it’s a literal tank (and that it was made a “hover” tank because of the strafe modifier). These games were released for DOS, where the mouse was optional, and all player input was through the digital keys of a computer keyboard.</p>

<p>Continuing the FPS trend, GoldenEye 64 uses tank controls. I don’t think any of us complained whilst playing 4 player split-screen back in the day - but then again, we didn’t have anything better to compare against (other than mouse &amp; keyboard FPS games).</p>

<h2 id="a-special-fps-game">A special FPS game</h2>

<p><a href="https://en.wikipedia.org/wiki/Resident_Evil_Survivor">Resident Evil Survivor</a>. It’s a game I feel I need to defend by itself, but I’ll leave that for another rambly blog post.</p>

<p><img src="https://felixjones.co.uk/assets/resi/re-survivor-zombie.jpeg" alt="Screenshot of Resident Evil Survivor. It is a first person game, the player is shooting a zombie." /></p>

<p>As with all PSX games, the game assumes the bareminum controls of the original PlayStation controller, with its digital old directions.</p>

<p>This game uses an FPS control scheme similar to what GoldenEye 64 uses, with tank controls and a dedicate “aim” button for moving the reticule, only with RE Survivor the <em>only</em> way to shoot the gun is to first aim.</p>

<p>After re-playing this game a number of times over the many years (it is very replayable) I had the epiphamy: The controls of this game are the <strong>same</strong> as the mainline Resident Evil games! Tank controls, hold button to aim/activate shooting, direction pad is used to adjust aiming (turning and aiming up/down).</p>

<h1 id="an-extra-rant-about-psx-vs-ps1">An extra rant about PSX vs PS1:</h1>

<p>Yes Sony made a console called the PSX which was a PS2. But we all called the PS1 the PSX back in the day. I have a theory that this comes from the codename for the original <a href="https://en.wikipedia.org/wiki/Super_NES_CD-ROM#Prototype">Nintendo PlayStation</a>, which has a chip with the markings “SFX” (not to be confused with the Super FX chip). When Sony moved onto the PlayStation they probably just replaced the Super Famicom with PlayStation to make PSX. Maybe the X means CD ROM eXpansion???.</p>

<hr />

<p>Alright, that’s the end of my ranting for today.</p>]]></content><author><name>Felix Jones</name></author><summary type="html"><![CDATA[Once again I am defending something that the collective internet has agreed sucks.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://felixjones.co.uk/assets/resi/dogs.jpeg" /><media:content medium="image" url="https://felixjones.co.uk/assets/resi/dogs.jpeg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>