<?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://www.maiakanegae.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.maiakanegae.com/" rel="alternate" type="text/html" /><updated>2026-07-24T00:40:51+00:00</updated><id>https://www.maiakanegae.com/feed.xml</id><title type="html">Maia Kanegae</title><subtitle>Software Engineer | London, UK | B.Sc. Computer Science @ ICMC/USP, Brazil</subtitle><entry><title type="html">Advent of Code 2020 in Review</title><link href="https://www.maiakanegae.com/advent-of-code-2020-in-review/" rel="alternate" type="text/html" title="Advent of Code 2020 in Review" /><published>2020-12-25T00:00:00+00:00</published><updated>2020-12-25T00:00:00+00:00</updated><id>https://www.maiakanegae.com/advent-of-code-2020-in-review</id><content type="html" xml:base="https://www.maiakanegae.com/advent-of-code-2020-in-review/"><![CDATA[<p><img src="/images/advent-of-code-2020-in-review/header.png" alt="" /></p>

<p>Happy Holidays! Here I am at the end of another year, having just finished <strong><a href="https://adventofcode.com/2020">Advent of Code 2020</a></strong>! If you are new to it, it’s an Advent calendar full of programming puzzles from December 1st all the way to Christmas, made by the amazing <a href="http://was.tl/">Eric Wastl</a> every year since 2015.</p>

<p>I’ve been participating since 2018 - <a href="/advent-of-code-2019-in-review/">here’s my comments on last year’s edition</a> -, and this time I actually tried my best to get some sweet leaderboard points! You can check my <strong>Python 3</strong> solutions on my <strong><a href="https://github.com/maiakanegae/advent-of-code">GitHub</a></strong>, and you can also <strong>keep reading for more info and my comments on the event.</strong></p>

<!--more-->
<hr />

<p>Once again, the event consists of 50 great programming puzzles, which also award <a href="https://adventofcode.com/2020/leaderboard">internet points and clout</a> for the first 100 people who complete each of them the fastest - again, as a reminder, <a href="https://www.reddit.com/r/adventofcode/comments/e2wjhf/tips_for_getting_on_the_advent_of_code_leaderboard/f90ksek/">it’s only a competition if you want it to be</a>. <strong>This year’s storyline was about you, the Christmas savior for 5 years in a row, finally taking a break, vacationing on a chill tropical island.</strong></p>

<p>As puzzles release at midnight EST/UTC-5, or 2AM my time, it’s often hard to be awake and ready to compete for leaderboard points. However, this year I did manage to be present for all puzzle release times, completing all of them in the following minutes/hours - which I consider a big personal accomplishment by itself. More than that, <strong>I also scored a total of 389 points over 6 leaderboard spots, placing me at 167th on the Global Leaderboard</strong>, topping last year’s score of 351 points at 196th place! Outside of the strict top 100, I managed to complete 25 of the puzzles - exactly half of them - in the top 500! It’s fair to note that <strong>this year had <a href="https://twitter.com/ericwastl/status/1333876936024743936">way more people participating</a>, so the leaderboard competition was far fiercer!</strong> If, in the future, you do feel like going down this route, I very much recommend <a href="https://blog.vero.site/post/advent-leaderboard">betaveros’, this year’s #1, blog post on How to Leaderboard</a>.</p>

<p>With all of those personal achievements in mind, I figured I would play a bit with some <a href="https://matplotlib.org/">Matplotlib</a>, and plotted a graph of my completion times and leaderboard positions! <strong>Top 100s are marked in red, and top 500s are in black.</strong> <a href="https://github.com/maiakanegae/advent-of-code/blob/main/2020/time-plots/time-plots.ipynb">Here’s the code that I wrote to generate it.</a></p>

<p><img src="/images/advent-of-code-2020-in-review/time-plot.png" alt="" /></p>

<p>Finally, <strong>a big thank you to all of the friends I managed to convince - or coerce - to join me on this month-long adventure</strong>, and a special shout out for those who were there with me over Discord every day at 2AM! Sharing strategies, solutions, celebrating leaderboard positions and just being together for some coding fun early in the morning was my highlight of this year’s event.</p>

<h3 id="notable-comments">Notable Comments</h3>

<p><strong><a href="https://adventofcode.com/2020/day/1">Day 1</a>:</strong> Apparently there were just too many people playing and <a href="https://www.reddit.com/r/adventofcode/comments/k4ejjz/2020_day_1_unlock_crash_postmortem/">the server decided to go for a walk</a>. Anyway, the first day was a small twist on the classic <a href="https://leetcode.com/problems/two-sum/">Two Sum</a> and <a href="https://leetcode.com/problems/3sum/">3Sum</a> problems.</p>

<p><strong><a href="https://adventofcode.com/2020/day/6">Day 6</a>:</strong> Out of all the days in which rookie mistakes cost me leaderboard spots, this one was the most impressive: I managed to completely misread the prompt and solved Part 2 before Part 1. Hooray?</p>

<p><strong><a href="https://adventofcode.com/2020/day/7">Day 7</a>:</strong> Recursion is fun! Great basic intro/refresher on the topic.</p>

<p><strong><a href="https://adventofcode.com/2020/day/10">Day 10</a>:</strong> Dynamic programming is… eh. Not that much well versed in it, so Part 2 took me a while. Shame on me, though, as this day’s puzzle was a simple variation of the classic <a href="https://leetcode.com/problems/climbing-stairs/">Climbing Stairs</a> problem.</p>

<p><strong><a href="https://adventofcode.com/2020/day/12">Day 12</a>:</strong> It took me so, so long to figure out the simple linear algebra to rotate the points around the origin. Lesson learned, definitely won’t forget that any time soon!</p>

<p><strong><a href="https://adventofcode.com/2020/day/13">Day 13</a>:</strong> Although very far from <a href="https://adventofcode.com/2019/day/22">the nightmare that was last year’s Day 22</a>, this was 2020’s Great Discrete Mathematics day. I quickly realized it had to be related to <a href="https://en.wikipedia.org/wiki/Modular_multiplicative_inverse">modular inverses</a> and that something was up with all bus IDs being prime, but connecting the dots to arrive on the <a href="https://brilliant.org/wiki/chinese-remainder-theorem/">Chinese Remainder Theorem</a> took an hour and change. Well needed refresher on Discrete Maths, once again!</p>

<p><strong><a href="https://adventofcode.com/2020/day/18">Day 18</a>:</strong> Simple and direct implementation of the <a href="https://en.wikipedia.org/wiki/Shunting-yard_algorithm">Shunting-yard algorithm</a>, which I had it implemented and ready to go from my first year’s A&amp;DS course at uni, but I totally did not realize that until after I solved it by <a href="https://realpython.com/operator-function-overloading/#overloading-built-in-operators">overloading the default integer operations</a>.</p>

<p><strong><a href="https://adventofcode.com/2020/day/19">Day 19</a>:</strong> All those Formal Languages classes came through! Great twist on Part 2 as well, making it a <a href="https://en.wikipedia.org/wiki/Context-free_grammar">CFG</a> and requiring an actual understanding of the rules. However, for both parts I considered that building the regular expression from the language rules was challenging enough so I left it at that, and broke my sacred rule of avoiding RegEx on AoC at all costs. Will definitely come back later and implement the actual language parsing.</p>

<p><strong><a href="https://adventofcode.com/2020/day/20">Day 20</a>:</strong> Oof. This one threw my sleep schedule completely over the window, as I spent 4 hours just to complete it plus another 3 to tidy up my code, and by that point it was already 9AM. But oh boy was it fun. Without a doubt my favorite of this year, implementing a jigsaw solver has been on my bucket list for years now, and the brain-teasing while doing it was simply amazing. I do want to shine some light on <a href="https://paiv.github.io/aoc2020/day/20/">paiv’s interactive version</a> as a fantastic tool to play around with, understand the puzzle itself or explain it to other people.</p>

<p><strong><a href="https://adventofcode.com/2020/day/23">Day 23</a>:</strong> At first I got spooked at the thought of it being another Discrete Maths one. After being stumped for a good hour or so, I had to grab a tip from the <a href="https://www.reddit.com/r/adventofcode/">Advent of Code’s subreddit</a>, and learned about the idea of combining a linked list and a hash map to fulfill the puzzle’s requirement of accessing arbitrary nodes in constant time. Cool!</p>

<p><strong><a href="https://adventofcode.com/2020/day/24">Day 24</a>:</strong> A fun twist on cellular automata, this time using a hexagonal grid. Luckily, I quickly realized I had done something like this before, on <a href="https://adventofcode.com/2017/day/11">Day 11 of AoC 2017</a>! <a href="https://www.redblobgames.com/grids/hexagons/">Here’s an amazing blog post from Red Blob Games on hexagonal grids</a>, which I used as a basis for both 2017’s edition and this one. If that piqued your interest, do check out their other posts, as they are all full of mindblowing insights!</p>

<p><strong><a href="https://adventofcode.com/2020/day/25">Day 25</a>:</strong> Another direct implementation, this time of brute-forcing a <a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange">Diffie-Hellman key exchange</a>. My RSA classes definitely helped!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Happy Holidays! Here I am at the end of another year, having just finished Advent of Code 2020! If you are new to it, it’s an Advent calendar full of programming puzzles from December 1st all the way to Christmas, made by the amazing Eric Wastl every year since 2015. I’ve been participating since 2018 - here’s my comments on last year’s edition -, and this time I actually tried my best to get some sweet leaderboard points! You can check my Python 3 solutions on my GitHub, and you can also keep reading for more info and my comments on the event.]]></summary></entry><entry><title type="html">Reverse engineering Lunia, my childhood MMORPG</title><link href="https://www.maiakanegae.com/reverse-engineering-lunia/" rel="alternate" type="text/html" title="Reverse engineering Lunia, my childhood MMORPG" /><published>2020-09-18T00:00:00+00:00</published><updated>2020-09-18T00:00:00+00:00</updated><id>https://www.maiakanegae.com/reverse-engineering-lunia</id><content type="html" xml:base="https://www.maiakanegae.com/reverse-engineering-lunia/"><![CDATA[<p><img src="/images/reverse-engineering-lunia/header.jpg" alt="" /></p>

<p><strong>Lunia</strong> was an <a href="https://en.wikipedia.org/wiki/Massively_multiplayer_online_role-playing_game">MMORPG</a> by South Korean producer <a href="http://www.allm.co.kr/">allm</a>, <strong>originally launched in early 2006</strong> and published in Brazil by <a href="https://levelupgames.uol.com.br/levelup/">Level Up! Games</a> in late 2008. Its main premise was being an MMORPG with heavy elements of an <a href="https://en.wikipedia.org/wiki/Beat_%27em_up">arcade beat ‘em up</a>, being one of the first to combine both genres.</p>

<p><strong>I started playing Lunia sometime in 2009</strong>, and it was what taught me fast typing, introduced me to online forums and communities, and gracefully presented me the world of MMOs in general. The game was the biggest time-sink of young me until late 2012, when the Brazilian servers shut down. Sadly, the global servers followed suit just a year after. It’s fair to say it was far from being the largest MMO at the time, but to 9-year-old me, it was golden.</p>

<p>Recently, I stumbled upon some screenshots buried deep in my file archives. After a couple days of reminiscing old times in some unofficial servers that are still around - and realizing the game aged surprisingly well (although it might be just my nostalgia talking) - <strong>I decided to use the skills that I acquired since then to snoop around the game files, maybe learning some cool stuff along the way. As it turns out, that was quite successful and exceedingly fun, so here’s a quite lengthy rundown of my journey.</strong></p>

<p>I probably spent over 150 hours in the last month to get up to this point, and <strong>it is still very much a work in progress</strong>. Many of the game files are still hidden or unexplored, and there’s a bunch that I still plan to do with the extracted assets. With that, I may update this post (or write follow-ups) in the near future if I do so.</p>

<!--more-->
<hr />

<h3 id="0-disclaimers">0. Disclaimers</h3>

<p>First of all, <strong>I am aware that the legality of this is a gray area</strong>. Although I’m pretty sure at this point Lunia could be categorized as <a href="https://en.wikipedia.org/wiki/Abandonware">abandonware</a>, I still don’t think sharing the game files are, legally speaking, a very good idea, so I won’t be releasing the decoded stuff here other than small snippets or screenshots. Still, if you want to try it yourself, all of the base files are somewhat easy to find if you know where to look for.</p>

<p>Secondly, most of this exploration was far out of my comfort zone. Other than a bunch of practice with Python scripts, I had barely any experience with most of the tech and strategies used here. <strong>Despite Computer Graphics being a field that I have always been very interested in, I had never touched 3D modeling, 3D animation, shaders and the like before this. Furthermore, my experience with reverse engineering in general is very, very brief, and game development was also never my thing, although I tried my hand at it a couple of times in the last years.</strong> Because of that, do take all of this with a big grain of salt: I’m sure there are many inaccuracies and false assumptions below. This was a great learning project starting from very little previous experience, so <strong>please do get in touch if you find anything out of place</strong>.</p>

<p>Based on both points above, <strong>this is not supposed to be a guide</strong>. This is more of a writeup from my exploration and storytelling of my discoveries. Although it’s not a tutorial, it probably serves as one if you ignore all my rambling. Also, I had no set goal at any stage whatsoever: I just kept taking whatever path I felt like and doing whatever I was up to at the time, so that’s why my steps may feel unordered and out of place.</p>

<p>Additionally, <strong>this is not an incentive or recommendation for you to play on an unofficial server</strong>. I won’t be giving any pointers on how to access them, but, again, the information is easily available online if you search for it. However, as Lunia is still “active”, from now on I will be talking about it in the present tense. Do be aware that, officially, the game servers - and, being an MMO, the game itself - are unavailable.</p>

<p>Finally, <strong>all of this was done solely for educational purposes</strong>. There is absolutely no intention of breaking copyright or redistributing any proprietary files, nor disrupting any active services. This is a writeup of a technical exploration fueled by curiosity, passion and nostalgia.</p>

<h3 id="1-what-is-lunia">1. What is Lunia?</h3>

<div style="width: ; margin: 0 auto;">

    <div class="ytcontainer">
        <iframe class="yt" src="https://www.youtube.com/embed/zu79QlykMxY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
    </div>
</div>

<p><strong>Lunia</strong>, originally called <strong>“Lunia: Record of Lunia War”</strong>, and in a later update renamed to <strong>“Lunia Z”</strong>, is an MMORPG with a big focus on <a href="https://en.wikipedia.org/wiki/Player_versus_environment">PvE content</a>, individual instanced stages and a rather linear progression - far from the open-world, quest-driven MMOs that dominate the market today. It consists of around 150 maps, or “stages”, of increasing difficulty, leveling your character from level 1 to 99. You can also be “reborn” once a month, as many times as you like: doing so resets your character back to level 1, giving you some cool stats bonuses and cosmetic wings in return, stacking up every time you rebirth. Most of the stages can be played with a party of up to 5 people, with a maximum party size of 12 for special maps or events. Lunia also has microtransactions, which definitely gives the game some “pay-to-win” vibes.</p>

<p>Instead of creating and customizing your character like you would in most MMOs nowadays, you choose from <strong>17 characters</strong> (originally just 3, with 14 more added to the roster via updates through the years), each having a well-defined place in Rodesia, the continent where Lunia takes place. Here’s the character creation screen:</p>

<p><img src="/images/reverse-engineering-lunia/character-creation.jpg" alt="" /></p>

<p>Just so you can follow along when I use any game-specific terms, here’s a brief description of the main stages and collections of them:</p>

<ul>
  <li><strong>Town Square:</strong> Main game hub, where most shops are located and players idle while fishing or selling stuff (more on this below).</li>
  <li><strong>History (Level 1-70):</strong> The game launched with only 3 episodes of 10 stages each, consisting of the main storyline. Later, it was gradually expanded to 7 episodes.</li>
  <li><strong>Legend (Level 30-70):</strong> Legend has the same first 6 episodes from History, with increased difficulty.</li>
  <li><strong>Bonus (Level 65+):</strong> Consists of 3 episodes with 7, 7, and 3 stages each, respectively. Longer levels with a big difficulty spike, hard to clear them by yourself. Gives some quite cool items and item sets. Each episode has a different theme and storyline.</li>
  <li><strong>Myth (Level 70+):</strong> Unlocks only after a rebirth. Has 6 stages and a somewhat long questline to unlock each of them. Gives exclusive item sets that can only be used in Myth/Devildom stages. Group content, not intended to be solo’d.</li>
  <li><strong>Devildom (Level 80+):</strong> Introduced very late into the game’s life, also requires a rebirth, and… I don’t know or remember that much, actually. Never reached that when I was little, and didn’t bother to play that much in unofficial servers.</li>
</ul>

<p><img src="/images/reverse-engineering-lunia/character-selection.jpg" alt="" /></p>

<p>Some other relevant (and fun!) game mechanics were:</p>

<ul>
  <li><strong>Trading, Personal Shops, and Open Market:</strong> Trade items and currency with other players directly, set up your shop at the Square while idle, or put your items up for sale in the Open Market for anyone to purchase at any time.</li>
  <li><strong>Player vs. Player:</strong> A dozen or so PvP arenas for up to 8-vs-8 combat.</li>
  <li><strong>Guilds:</strong> Communities of up to 200 players, with extra perks when playing together.</li>
  <li><strong>Families:</strong> Essentially smaller guilds of up to 5 people, originally made to pair new players with experienced ones.</li>
  <li><strong>Item “fortification” and “light fortification”:</strong> Improve your items by spending reagents, heavily based on RNG. The latter would also make your equipment shinier.</li>
  <li><strong>Fishing:</strong> Leave your character fishing while idle to turn bait into various types of fishes, which can be sold for gold or traded with NPCs for many valuable items and resources.</li>
  <li><strong>Pets:</strong> Choose between dogs, cats, fairies, dragons, unicorns, and a dozen other small creatures that follow you around and give you stat bonuses - but only if you feed them.</li>
  <li><strong>Slime Racing:</strong> Bet coins on a fully RNG-based NPC race. Basically a <a href="https://en.wikipedia.org/wiki/Roulette">Roulette</a> numbered from 1 to 9.</li>
  <li><strong>Achievements:</strong> Complete various milestones and rack up achievement points, which in turn gives you some colored stars after your name for clout.</li>
</ul>

<p><img src="/images/reverse-engineering-lunia/game-fishing.jpg" alt="" /></p>

<p>While looking for some information about Lunia (which the internet has surprisingly little of), I found <strong>two series of articles by IGN from 2007, sometime around the North America open beta launch</strong>, talking about the game’s initial premise and development, and they’re quite detailed. Here’s <strong><a href="https://www.ign.com/articles/2007/06/19/record-of-lunia-war-interview-part-1">Record of Lunia War Interview Part 1</a> and <a href="https://www.ign.com/articles/2007/06/26/record-of-lunia-war-interview-part-2">Part 2</a></strong>, as well as <strong><a href="https://www.ign.com/articles/2007/09/13/record-of-lunia-war-diary-1">Record of Lunia War Diary #1</a>, <a href="https://www.ign.com/articles/2007/09/21/record-of-lunia-war-diary-2">#2</a>, <a href="https://www.ign.com/articles/2007/09/28/record-of-lunia-war-diary-3">#3</a> and <a href="https://www.ign.com/articles/2007/10/09/record-of-lunia-war-diary-4">#4</a></strong>, both of which were a great read before cracking the game open.</p>

<h3 id="2-scratching-the-surface">2. Scratching the Surface</h3>

<p>Initially, what I had to play around with were the game client files. I managed to get my hands in two clients from different unofficial servers, as well as the original one from the old days of the Brazilian server. I later found out that there were no big differences between the three of them other than the localization, so from now on, I’ll be referring to all of them as a single client. Here’s the <strong>game root directory</strong>, with a total size of around 1.5GB:</p>

<p><img src="/images/reverse-engineering-lunia/folder-root.png" alt="" /></p>

<p>Together with the obvious game executables and cursor icons, most of the files at the root were configuration files. Key bindings, player preferences and graphics options, all stored in <code class="language-plaintext highlighter-rouge">.xml</code> text files with a bunch of comments in Korean. <strong>A few <code class="language-plaintext highlighter-rouge">.dll</code>s that grabbed my attention were <a href="https://en.wikipedia.org/wiki/Adobe_Flash"><code class="language-plaintext highlighter-rouge">FlashPlayer.dll</code></a>, <a href="https://en.wikipedia.org/wiki/Lua_(programming_language)"><code class="language-plaintext highlighter-rouge">lua50.dll and tolua++.dll</code></a>, <a href="https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Markov_chain_algorithm"><code class="language-plaintext highlighter-rouge">LZMA.dll</code></a>, and half a dozen with  “<a href="https://en.wikipedia.org/wiki/CEGUI"><code class="language-plaintext highlighter-rouge">CEGUI</code></a>” in the filename.</strong></p>

<p>The <code class="language-plaintext highlighter-rouge">Cinema/</code> and <code class="language-plaintext highlighter-rouge">Flash/</code> directories contained hundreds of <code class="language-plaintext highlighter-rouge">.swf</code> files that can be viewed with something like <a href="http://www.swffileplayer.com/">SWF File Player</a>. Those are all <strong>Flash animations that are extensively used throughout the game</strong>. Alongside some of them, there were also a few sprites in the <a href="https://en.wikipedia.org/wiki/DirectDraw_Surface"><code class="language-plaintext highlighter-rouge">.dds</code></a> format. <code class="language-plaintext highlighter-rouge">Sounds/</code> had a hundred <code class="language-plaintext highlighter-rouge">.ogg</code> and <code class="language-plaintext highlighter-rouge">.wav</code> sound files, which were <strong>the game’s main theme songs, a bunch of background music and general ambience SFX</strong>. It also contained files <code class="language-plaintext highlighter-rouge">Sounds.cfp</code> and <code class="language-plaintext highlighter-rouge">Sounds.cpv</code>, extensions that I had never seen before.</p>

<p>All the other folders (<code class="language-plaintext highlighter-rouge">Animation/</code>, <code class="language-plaintext highlighter-rouge">Database/</code>, <code class="language-plaintext highlighter-rouge">Display/</code>, <code class="language-plaintext highlighter-rouge">Locales/</code>, <code class="language-plaintext highlighter-rouge">Mapping/</code>, <code class="language-plaintext highlighter-rouge">Maps/</code>, <code class="language-plaintext highlighter-rouge">Shaders/</code> and <code class="language-plaintext highlighter-rouge">UI2/</code>) had only two files in each of them: a <code class="language-plaintext highlighter-rouge">.cfp</code> and <code class="language-plaintext highlighter-rouge">.cpv</code>, named the same as each of their respective parent directories, exactly like the ones at <code class="language-plaintext highlighter-rouge">Sounds/</code>.</p>

<p>When trying to figure out what those two file types were, no obvious result showed up. Only when searching for the extensions together with “Lunia”, I managed to find some forums posts that guided me to <a href="http://aluigi.altervista.org/quickbms.htm">QuickBMS</a>, which has <strong>a handy unpack script for <code class="language-plaintext highlighter-rouge">.cfp</code> files</strong>, seemingly Lunia-exclusive. Upon inspecting the script, <strong>the file type is a simple binary file with a bunch of string filenames and its LZMA-compressed binary data</strong> (hence the <code class="language-plaintext highlighter-rouge">LZMA.dll</code> found earlier!) concatenated. As for their <code class="language-plaintext highlighter-rouge">.cpv</code> counterpart, they went completely unused by the script without any data missing as a result. By looking at its binary data, my best guess is that they simply serve as index tables for the game to be able to directly locate any specific file inside the archive. When extracted, the 1.2GB collection of 9 pairs of <code class="language-plaintext highlighter-rouge">.cfp</code> and <code class="language-plaintext highlighter-rouge">.cpv</code> files turned into over 130.000 files, totaling around 4GB:</p>

<p><img src="/images/reverse-engineering-lunia/folder-cfp-extracted.png" alt="" /></p>

<p>There we go! Here are the interesting pieces that were unlocked by simply extracting the archives:</p>

<ul>
  <li><strong>Over 25.000 item and skill icons</strong> at <code class="language-plaintext highlighter-rouge">Display/Textures/</code>, all in <code class="language-plaintext highlighter-rouge">.dds</code> format (screenshot below).</li>
  <li><strong>All game strings</strong> at <code class="language-plaintext highlighter-rouge">Locales/</code>, in more weirdly ancient <code class="language-plaintext highlighter-rouge">.xml</code> text files. Quest texts, NPC phrases, item and skill names/descriptions, achievements and everything else.</li>
  <li><strong>Over 15.000 <code class="language-plaintext highlighter-rouge">.dds</code> textures for every single 3D model in the game</strong> at <code class="language-plaintext highlighter-rouge">Mapping/</code>, from characters to pieces of equipment to skill effects (screenshot below). There were also around a hundred textures for the stages’ visual elements (trees, rocks, buildings…) at <code class="language-plaintext highlighter-rouge">Maps/*/Shared/</code>.</li>
  <li><strong>Hit sounds, character attacks’ SFX, voice lines and a bunch of other sound snippets</strong> at <code class="language-plaintext highlighter-rouge">Sounds/</code> all in the same <code class="language-plaintext highlighter-rouge">.ogg</code> and <code class="language-plaintext highlighter-rouge">.wav</code> formats, along with copies of the same ambiance sounds and background music that was outside the <code class="language-plaintext highlighter-rouge">.cfp</code> archive, for some reason.</li>
  <li><strong>All UI visual elements</strong> as <code class="language-plaintext highlighter-rouge">.tga</code> files and more <code class="language-plaintext highlighter-rouge">.swf</code> animations at <code class="language-plaintext highlighter-rouge">UI2/</code>, mainly inside <code class="language-plaintext highlighter-rouge">UI2/imagesets/</code> and <code class="language-plaintext highlighter-rouge">UI2/Stage/</code>.</li>
  <li>A lot of simple text files with different extensions everywhere. Some of them describing UI element positioning (<code class="language-plaintext highlighter-rouge">.layout</code>, <code class="language-plaintext highlighter-rouge">.looknfeel</code>), and mainly a load of <code class="language-plaintext highlighter-rouge">.xml</code> detailing camera configurations, coordinates for asset placement in stages, and just generally referencing assets via their file paths.</li>
</ul>

<p><img src="/images/reverse-engineering-lunia/folder-icons.jpg" alt="" /></p>

<p>For the image assets, <a href="https://www.xnview.com/en/xnconvert/">XnConvert</a> made it easy to batch convert both <code class="language-plaintext highlighter-rouge">.dds</code> and <code class="language-plaintext highlighter-rouge">.tga</code> file types to the more common <code class="language-plaintext highlighter-rouge">.png</code> extension.</p>

<p><img src="/images/reverse-engineering-lunia/folder-textures.jpg" alt="" /></p>

<p>However, a lot of points still left me puzzled:</p>

<ul>
  <li>Most of the files at <code class="language-plaintext highlighter-rouge">Shaders/</code> were <code class="language-plaintext highlighter-rouge">.fxc</code> ones. Upon further research, those appeared to be <strong>compiled <a href="https://en.wikipedia.org/wiki/High-Level_Shading_Language">HLSL</a> shaders</strong>. As Lunia’s minimum requirements ask for <a href="https://en.wikipedia.org/wiki/DirectX">DirectX 9.0</a>, that made sense. However, as those are compiled files, trying to decompile those seemed way out of my league - or interest - at this moment.</li>
  <li>Lots of stuff in <code class="language-plaintext highlighter-rouge">Animation/</code> were <strong><code class="language-plaintext highlighter-rouge">.SkinnedMesh</code>, <code class="language-plaintext highlighter-rouge">.Skeleton</code> and <code class="language-plaintext highlighter-rouge">.SkinnedAnim</code> files, with more at <code class="language-plaintext highlighter-rouge">Maps/*/Objects</code>, all seemingly custom formats</strong>, specific for Lunia. No obvious way of opening them, but I suspected those contained the 3D models, armatures/rigging and animation sequences, respectively.</li>
  <li>The <code class="language-plaintext highlighter-rouge">.LuniaMap</code> files in <code class="language-plaintext highlighter-rouge">Maps/</code> probably described the stage, I supposed. Also seems to be completely custom.</li>
  <li><strong>Where are the fonts?</strong> <code class="language-plaintext highlighter-rouge">UI2/fonts/</code> had a ton of <code class="language-plaintext highlighter-rouge">.xml</code> defining different font styles by having different variables in them, but no <code class="language-plaintext highlighter-rouge">.ttf</code> files like I was expecting. However, <code class="language-plaintext highlighter-rouge">Shaders/</code> had a couple <code class="language-plaintext highlighter-rouge">.fxc</code> with a pairing <code class="language-plaintext highlighter-rouge">.fx</code> of the same name. When opening one of them (screenshot below), it surely had something to do with rendering text. Could the fonts be fully rendered via shaders? Is that even possible?</li>
  <li><strong>What about all the equipment stats, drop tables, and all the numbers that a hardcore player would love to have at hand?</strong> I supposed that for bigger flexibility for balancing tweaks and the like, those would not be in the client files, but server-side.</li>
</ul>

<p><img src="/images/reverse-engineering-lunia/text-shader-file.png" alt="" /></p>

<p>It’s also interesting to note the information in the file header: <strong>the game is referenced as <code class="language-plaintext highlighter-rouge">Lunia Project</code>; the file author, <code class="language-plaintext highlighter-rouge">juhnu</code>, is possibly <a href="https://www.linkedin.com/in/juhanihonkala/">Juhani Honkala</a>, who is credited as “Lead Graphics Programmer / Technical Director”; and the file date, 2004</strong> - Lunia was launched in 2006.</p>

<p>At this point, after some days of exploring all files and reading most of them from top to bottom while trying to understand how the big web of <code class="language-plaintext highlighter-rouge">.xml</code> files relate to each other, I got pretty tired of that. Being happy as a result of extracting all item and skill icons as well as all UI elements, I felt like playing with them for a bit…</p>

<h3 id="3-playing-with-ui">3. Playing with UI</h3>

<p>It had been a few years since I had last made a project with a graphical interface. With the spark of motivation from having those thousands of 32x32 icons in hand, I felt like <strong>coding a clone of Lunia’s inventory window</strong>. Here it is, in-game:</p>

<p><img src="/images/reverse-engineering-lunia/game-inventory.jpg" alt="" /></p>

<p>Although I’m almost completely sure Python is not the greatest tool for that, it is the one I am most comfortable with, so <strong>I chose <a href="https://www.pygame.org/wiki/GettingStarted">Pygame</a> as the graphical library</strong>. I had tried to use it a couple times in the past, but never managed to build anything that looked polished enough, probably for the lack of general programming experience at the time.</p>

<p>One common misconception is that Pygame is a game engine. It’s actually way lower level than that: <strong>Pygame is a set of Python modules built on top of <a href="http://www.libsdl.org/">SDL</a></strong>, but, for my specific use case, it served mostly as a simple library that allowed me to draw images at certain positions a bunch of times a second. And having to write code to make higher-level functions out of that is exactly my cup of tea.</p>

<p>I first started taking screenshots of Lunia’s inventory and modifying pixels here and there, like expanding the item slots to a single 8x8 grid instead of 7 separate 5x4 bags, simplifying the equipment tabs to only one and removing the currency altogether. After a while of getting a feel for Pygame, <strong>I managed to make the item icons draggable, have them snap to the actual slots, draw that cute hover effect and have a solid back-end for all of that: well-thought-out data structures to store inventory and item properties</strong>. It was at this point I realized I needed a big refresher on some Object-Oriented Programming concepts, which led me to one of <a href="https://youtu.be/HTLu2DFOdTg">Raymond Hettinger’s talks</a> - Hettinger has done excellent work as a Python Core Developer, and if you consider yourself an intermediate Python developer, I highly recommend watching <a href="https://www.youtube.com/playlist?list=PLRVdut2KPAguz3xcd22i_o_onnmDKj3MA">all of his talks</a>, which was exactly what I did in the days that followed: binge-watched them as if they were a Netflix show.</p>

<video src="/images/reverse-engineering-lunia/pygame-1.mp4" controls="" preload="metadata" loop="">
</video>

<p>The next challenge was to <strong>show the item quantities, in the lower right corner of their icons</strong>. Of course, a requirement for that would be the fonts, which I still hadn’t managed to find in the game files. With that, I decided to just screenshot the numerical characters and manually create a spritesheet with Photoshop and some patience. Next, some more hours of work went by to build higher-level functions that drew strings of numbers at the appropriate positions.</p>

<p>Then, I spent some more days refining the code (and rewriting it all from scratch to apply my newly gained Pygame and OOP knowledge) and implementing some of the remaining, most obvious features: <strong>item swapping, equipping and unequipping, stacking and splitting</strong>, and a bunch of other small touch-ups. It’s at those times you stop to appreciate the fine art of UI/UX development: it turns out game UIs have so many small details that we take for granted when playing but stick out like a sore thumb when you forget to implement them.</p>

<video src="/images/reverse-engineering-lunia/pygame-2.mp4" controls="" preload="metadata" loop="">
</video>

<p>For my next trick, I figured I would try to <strong>draw the description textboxes</strong>. You know, when you hover over the item, and a textbox pops up with its name, properties, stats, description, and all the cool stuff? Here’s another screenshot showing the original thing:</p>

<p><img src="/images/reverse-engineering-lunia/game-item.jpg" alt="" /></p>

<p>Great! Now I just grab the font files and… well, there are none. I will have to make them by hand, again. After a bit of in-game exploration, it turns out <strong>all of the fonts used throughout Lunia can be summed up in four styles</strong>, three of them present in the screenshot above: <strong>regular</strong> (e.g. currency amount, at the bottom), <strong>bold</strong> (e.g. item description textbox, window title), <strong>regular with stroke</strong> (e.g. equipment tabs, at the top), and <strong>bold with stroke</strong>. As shown, they can be in varying colors (and stroke colors), and sometimes even sizes - I chose to ignore different text sizes for now. Upon further inspection, all of the styles derived from the basic, regular one: the stroke is done by simply painting the <a href="https://en.wikipedia.org/wiki/Pixel_connectivity">4-connected</a> pixels, and the bold sprite is simply two of the regular one, the second being drawn offset one pixel to the right.</p>

<p>Well, I once again built the characters’ spritesheets by hand. Thankfully, as with most of the game’s assets, they are quite fixed in size and there’s no anti-aliasing at all, giving them that pixel-art feel which I adore. Having the four spritesheets ready (which could be just the regular one, but I figured it was easier to “harddraw” all of them instead of using code to apply the bold and stroke effects), some more days went by on writing <strong>a very flexible and optimized text drawing module, complete with text coloring, left/center/right alignment, line breaks and text wrapping</strong>. The character widths are variable, but the heights are, for the most part, constant. However, the horizontal spacing is quite wonky. For my implementation, I decided to ditch any attempt at <a href="https://en.wikipedia.org/wiki/Kerning">kerning</a> and just set a constant 1-pixel spacing for every character, which, if I do say so myself, turned out better than the game itself. To test it isolated from the rest, I decided to write <strong>a basic text editor</strong>:</p>

<video src="/images/reverse-engineering-lunia/pygame-3-text-editor.mp4" controls="" preload="metadata" loop="">
</video>

<p>With that out of the way, I rewrote the code for the item quantities to now use the shiny text module. As a bonus, I also used it to <strong>draw the window title, now being able to freely rewrite it instead of being baked into the background</strong>. Cool! Now I just have to draw the description textbox itself, and… then I realized that’s not going to fit into my measly inventory window.</p>

<p>Okay, I could simply make the application window larger, but where’s the fun in that? <strong>What if I made the window draggable?</strong> Of course, that meant having to basically rewrite the whole thing once again as to, per best OOP practices, have a <code class="language-plaintext highlighter-rouge">Window</code> base class for every other window to inherit from. In turn, that would give me not only draggable windows, but multiple ones. <strong>And they may have different sizes and titles. And they may overlap. And I would have to deal with how to choose which one to send input info to.</strong> At this point, the project scope exploded, and I decided to just go for it. After a couple more days, <strong>I now had a full window manager thing going on</strong>. Once again, many small UI/UX elements and concepts that I always took for granted and had to account for.</p>

<video src="/images/reverse-engineering-lunia/pygame-4-window-manager.mp4" controls="" preload="metadata" loop="">
</video>

<p>I then rewrote most of the initial project’s code, <strong>adding another window modeled after one of the game’s fishing windows</strong>, with the (fake, fixed) total fish counts. Some more hours into a new description textbox module, and another bunch into building <strong>a parser to process formatting tags</strong> for me to easily mix and match different colors in a single block of text…</p>

<video src="/images/reverse-engineering-lunia/pygame-5.mp4" controls="" preload="metadata" loop="">
</video>

<p>For now, the large item description and stats shown are hard-coded. I had the item names and descriptions from the localization files, but not the stats or the other properties. However, the code is flexible enough to handle that whenever I get my hands on them. Also, I later packed up all 25.000+ icons into a single spritesheet using <a href="https://www.codeandweb.com/sprite-sheet-maker">TexturePacker</a>, as that makes loading them into memory way quicker.</p>

<p>As the video compression kinda kills it, here’s an <strong>uncompressed side-by-side comparison of the textboxes, with Lunia’s on the left and mine on the right, together with the source text with my formatting tags used to generate it</strong>:</p>

<p><img src="/images/reverse-engineering-lunia/textboxes-comparison.png" alt="" /></p>

<p>All in all, the window manager / inventory clone runs at around 500-700 FPS on my machine (Ryzen 5 3600), with lots of pending optimizations still. Of course, there’s a lot more that can be done, and I do plan on spending way more time working on it. One of the ideas that sounded interesting at that moment was to <strong>build some sort of model viewer, so I could have my 3D character dressed up with the currently equipped items</strong>. However, to do that, I would need the actual 3D models, of course. So, I went back to scavenging…</p>

<h3 id="4-3d-meshes">4. 3D Meshes</h3>

<p>I had never fiddled with 3D stuff before, but I knew some basic concepts and I’ve been wanting to play with modeling for quite a while now. Having barely any previous experience meant that trying to reverse engineer Lunia’s 3D files was a quite daunting task. Well, <strong>I already had all the models’ textures, but not the models themselves</strong>. My best guess was still the <code class="language-plaintext highlighter-rouge">Animations/</code> directory: if I navigated to <code class="language-plaintext highlighter-rouge">Animations/AlliedNPC/BankClerk/</code>, here’s what I got, alongside the Bank NPC at the Square, which I assumed the files represented:</p>

<p><img src="/images/reverse-engineering-lunia/model-files.jpg" alt="" /></p>

<p><code class="language-plaintext highlighter-rouge">BankClerk.material.xml</code> referenced the model texture located at <code class="language-plaintext highlighter-rouge">Mapping/</code>; <code class="language-plaintext highlighter-rouge">BankClerk.animation.xml</code> linked the <code class="language-plaintext highlighter-rouge">.Skeleton</code> and <code class="language-plaintext highlighter-rouge">.SkinnedAnim</code> files, and set the animation variables <code class="language-plaintext highlighter-rouge">speed</code> to <code class="language-plaintext highlighter-rouge">30</code> and <code class="language-plaintext highlighter-rouge">playback</code> to <code class="language-plaintext highlighter-rouge">2</code>, whatever those meant; and <code class="language-plaintext highlighter-rouge">BankClerk.xml</code> simply defined an object of type <code class="language-plaintext highlighter-rouge">Character::SkinnedModelInfo</code> that tied everything together.</p>

<p>After lots of searching around the web for something that could make some sense of those files, I finally found <strong><a href="https://richwhitehouse.com/index.php?content=inc_projects.php&amp;showproject=91">Noesis</a>, which seemed to be a tool for opening and converting 3D models</strong>, with an easy API for people to write <a href="https://himeworks.com/noesis-plugins/">plugins</a> for custom file types. With the program itself, I also found <strong>a <a href="https://himeworks.com/redirect.php?type=noesis&amp;name=Lunia_skinnedmesh">custom plugin for <code class="language-plaintext highlighter-rouge">.SkinnedMesh</code> files</a></strong>. Bingo!</p>

<p><img src="/images/reverse-engineering-lunia/model-noesis.png" alt="" /></p>

<p>Well, Noesis has 20 or so file extensions for me to choose from, and none of them were familiar to me. Here’s when I realized <strong>I would have to pause for a while and learn a bit about 3D animation before continuing</strong>. First, I decided to set the initial goal of being able to export the models (textured, of course) to something like <a href="https://www.blender.org/">Blender</a>. I also quickly found out that the most friendly, and possibly common, filetype for 3D models is the <a href="https://en.wikipedia.org/wiki/Wavefront_.obj_file"><code class="language-plaintext highlighter-rouge">.obj</code></a> extension.</p>

<p>To start, I learned that a (basic) textured 3D model consists of:</p>
<ul>
  <li>A list of <strong>vertices</strong>, or 3D points, usually represented by 3 <code class="language-plaintext highlighter-rouge">float</code>s.</li>
  <li>A list of <strong>faces</strong>, <a href="https://youtu.be/U93RImC-by4">usually</a> of <a href="https://gamedev.stackexchange.com/questions/66312/quads-vs-triangles/66314#66314">triangles</a>, each defined by a subset of the vertices. Together with the vertices, they form the model’s mesh.</li>
  <li>A flat <strong>texture file</strong>, usually a square image.</li>
  <li>A <strong><a href="https://en.wikipedia.org/wiki/UV_mapping">UV map</a></strong>, which defines the relationship (mapping) between the mesh and the texture.</li>
</ul>

<p>Well, I already had the texture file. Maybe the other 3 elements were in the <code class="language-plaintext highlighter-rouge">.SkinnedMesh</code> that Noesis loaded? Indeed they were, plus a list of <a href="https://en.wikipedia.org/wiki/Vertex_normal">vertex normals</a>, which were all successfully exported to an <code class="language-plaintext highlighter-rouge">.obj</code> file. I then spent a few hours learning Blender’s interface and key bindings, imported the newly generated file, and all was good. But when trying to add in the texture, the UV map seemed a little bit out of place…</p>

<p><img src="/images/reverse-engineering-lunia/blender-uv-map-1.jpg" alt="" /></p>

<p>Although using <code class="language-plaintext highlighter-rouge">sy-1</code> (Blender shortcut for “scale -100% in the y axis”) seemed to fix it, it also introduced a subtle vertical offset. It’s easy to notice the texture being a bit out of place on the character’s shoes:</p>

<p><img src="/images/reverse-engineering-lunia/blender-uv-map-2.jpg" alt="" /></p>

<p>I figured I would try to modify the conversion script so it flipped the UV map on the y axis by applying the transformation <code class="language-plaintext highlighter-rouge">(x, y) -&gt; (x, 1-y)</code> on all vertices (the <code class="language-plaintext highlighter-rouge">Flip UV's</code> option in Noesis flips it in the x axis instead). However, to do that, I was forced to understand what the script was doing, and, consequently, what exactly that custom filetype was. After exploring the script and the file’s binary data, the (almost) full definition of the <code class="language-plaintext highlighter-rouge">.SkinnedMesh</code> filetype is:</p>

<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="c1">// Little Endian</span>
<span class="c1">// 4-byte ints, 4-byte floats, 2-byte shorts, 2-byte chars (UTF-16)</span>

<span class="kt">int</span> <span class="n">N</span><span class="p">;</span> <span class="c1">// length of the model name</span>
<span class="kt">char</span><span class="p">[</span><span class="n">N</span><span class="p">]</span> <span class="n">modelName</span><span class="p">;</span> <span class="c1">// string for model name, ending with 0x0000 (\0)</span>
<span class="kt">int</span> <span class="n">V</span><span class="p">;</span> <span class="c1">// # of mesh vertices</span>
<span class="kt">int</span> <span class="n">I</span><span class="p">;</span> <span class="c1">// # of mesh vertex indexes (3 * # of faces)</span>
<span class="kt">int</span> <span class="n">unknown</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span> <span class="c1">// unknown</span>
<span class="kt">short</span> <span class="n">faces</span><span class="p">[</span><span class="n">I</span><span class="p">];</span> <span class="c1">// mesh faces, 3 by 3</span>
<span class="kt">int</span> <span class="n">V</span><span class="p">;</span> <span class="c1">// # of mesh vertices (same as before)</span>
<span class="kt">float</span> <span class="n">vertices</span><span class="p">[</span><span class="mi">3</span><span class="o">*</span><span class="n">V</span><span class="p">];</span> <span class="c1">// mesh vertices, 3 by 3</span>
<span class="kt">int</span> <span class="n">V</span><span class="p">;</span> <span class="c1">// # of mesh vertices (same as before)</span>
<span class="kt">float</span> <span class="n">vertexNormals</span><span class="p">[</span><span class="mi">3</span><span class="o">*</span><span class="n">V</span><span class="p">];</span> <span class="c1">// vertex normals, 3 by 3</span>
<span class="kt">int</span> <span class="n">V</span><span class="p">;</span> <span class="c1">// # of mesh vertices (same as before)</span>
<span class="kt">float</span> <span class="n">uvMap</span><span class="p">[</span><span class="mi">2</span><span class="o">*</span><span class="n">V</span><span class="p">];</span> <span class="c1">// UV map vertices, 2 by 2</span>
<span class="kt">int</span> <span class="n">V</span><span class="p">;</span> <span class="c1">// # of mesh vertices (same as before)</span>
<span class="c1">// a lot more data, unknown</span></code></pre></figure>

<p>And it worked, without the small inaccuracies inserted by Blender! Here’s a more pronounced example, in which the back model was the one that had the UV map flipped by Blender, and the one on the foreground had it flipped by my modified script:</p>

<p><img src="/images/reverse-engineering-lunia/blender-uv-map-3.jpg" alt="" /></p>

<p>Here’s the snippet of (really ugly) Python code that I wrote to flip the y coordinate of all UV map vertices:</p>

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">uvMap</span> <span class="o">=</span> <span class="nb">bytearray</span><span class="p">(</span><span class="n">uvMap</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">uvMap</span><span class="p">),</span> <span class="mi">4</span><span class="o">*</span><span class="mi">2</span><span class="p">):</span>
    <span class="n">y</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"f"</span><span class="p">,</span> <span class="n">uvMap</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span><span class="o">+</span><span class="mi">4</span><span class="p">])[</span><span class="mi">0</span><span class="p">]</span>
    <span class="n">uvMap</span><span class="p">[</span><span class="n">i</span><span class="p">:</span><span class="n">i</span><span class="o">+</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="n">struct</span><span class="p">.</span><span class="n">pack</span><span class="p">(</span><span class="s">"f"</span><span class="p">,</span> <span class="mi">1</span><span class="o">-</span><span class="n">y</span><span class="p">)</span>
<span class="n">uvMap</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">(</span><span class="n">uvMap</span><span class="p">)</span></code></pre></figure>

<p>With that fix, around a dozen Blender tutorials, and going face first into that rabbit hole, I exported some other models and textures and rendered a basic scene:</p>

<p><img src="/images/reverse-engineering-lunia/blender-render.jpg" alt="" /></p>

<p>It’s interesting to note that, for the character on the right, I had to piece together the models for each body part, as there’s an individual model for every piece of equipment in the game. I decided to pick my favorite equipment set: the one from the Forest of Water (Myth 2), which matches the one my character is wearing in some of the screenshots shown earlier in this post. <strong>It’s also clearly <a href="https://en.wikipedia.org/wiki/T-pose">in a different pose</a> than in-game, I wonder why…</strong></p>

<h3 id="5-3d-rigging-and-animations">5. 3D Rigging and Animations</h3>

<p>A <a href="https://en.wikipedia.org/wiki/Skeletal_animation">3D rig</a>, also known as an armature or skeleton, is a collection of “bones” that each relates to a subset of vertices from its mesh and may be connected between themselves. They mainly serve as <strong>a tool for creating smooth animations for the model by automatically deforming the appropriate vertices</strong> without having to manually manipulate every single one of them for every animation frame. Most rigged models are usually related to characters, but anything that moves may have a skeleton as well. In the context of Lunia, other than all playable and non-playable characters, most of the spells also have an armature attached.</p>

<p>With that in mind, it became pretty clear that <code class="language-plaintext highlighter-rouge">.Skeleton</code> probably defines the bones, and <code class="language-plaintext highlighter-rouge">.SkinnedAnim</code> should list a series of frames and the rig’s movement between them. Unfortunately, <strong>I couldn’t find any previous work done on any of those files anywhere on the web</strong>. Although that Noesis plugin handled the meshes, there’s absolutely nothing regarding armatures or their animations. So this time I had to go barehanded.</p>

<p>At this point, the <code class="language-plaintext highlighter-rouge">BankClerk</code> model was the one I was the most familiar with, and <strong>it looked as simple as a humanoid model could get</strong>, he only had one of each: <code class="language-plaintext highlighter-rouge">.SkinnedMesh</code>; <code class="language-plaintext highlighter-rouge">.Skeleton</code>; and <code class="language-plaintext highlighter-rouge">.SkinnedAnim</code>, and being a humanoid, I figured his correct skeleton and movements would be quite easy to recognize. With most of the <code class="language-plaintext highlighter-rouge">.SkinnedMesh</code> figured out and the assumption that <code class="language-plaintext highlighter-rouge">.SkinnedAnim</code> probably acts on the <code class="language-plaintext highlighter-rouge">.Skeleton</code>, it was easy to choose the next one to tackle.</p>

<p>This was my first time analyzing a binary with no information before. I thought a first good step would be to open a couple other <code class="language-plaintext highlighter-rouge">.Skeleton</code> files as well, so I chose <code class="language-plaintext highlighter-rouge">Animal\Bear\Bear.Skeleton</code> and <code class="language-plaintext highlighter-rouge">AlliedNPC\Knight\Knight.Skeleton</code> and kept comparing the three of them with each other to spot similarities and differences.</p>

<p><strong>The <code class="language-plaintext highlighter-rouge">BankClerk.Skeleton</code> file had 6880 bytes in total.</strong> Here’s the most interesting parts of the file’s binary data, from <a href="https://hexed.it/">HexEd.it</a>:</p>

<p><img src="/images/reverse-engineering-lunia/bank-skeleton-hex-cut.png" alt="" /></p>

<p>Based on some assumptions taken from the <code class="language-plaintext highlighter-rouge">.SkinnedMesh</code> exploration, I started taking notes. Well, the first bytes seemed simple enough: some UTF-16 strings containing what looked like file paths…? Considering the <code class="language-plaintext highlighter-rouge">SolidMaterialGroup.Xml</code> string, I supposed they referenced the other related files. Next, I spotted quite a couple <code class="language-plaintext highlighter-rouge">FF FF FF FF</code> sequences: they seemed to be <strong>separators for different data sections</strong>: whenever the byte patterns changed, there was a <code class="language-plaintext highlighter-rouge">FF FF FF FF</code> between both parts.</p>

<p>After the UTF-16 strings section, there were <strong>38 UTF-8 strings of 128 bytes each</strong>, zero-padded, of quite suggestive content, leading me to believe they were all <strong>bone names</strong>: <code class="language-plaintext highlighter-rouge">Base</code>, <code class="language-plaintext highlighter-rouge">Waist</code>, <code class="language-plaintext highlighter-rouge">Chest</code>, <code class="language-plaintext highlighter-rouge">Chest1</code>, <code class="language-plaintext highlighter-rouge">L_Shoulder</code>, <code class="language-plaintext highlighter-rouge">L_UpperArm</code>, all the way to <code class="language-plaintext highlighter-rouge">R_Thigh</code>, <code class="language-plaintext highlighter-rouge">R_Calf</code>, <code class="language-plaintext highlighter-rouge">R_Foot</code> and so on. I wonder why they are all of fixed length, as most of the 128 bytes for each string are wasted.</p>

<p>After that (if you are following along on the image, this is at line <code class="language-plaintext highlighter-rouge">00001420</code>), comes:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">00 04 00 03</code>: I had no idea what those are, but they are in all <code class="language-plaintext highlighter-rouge">.Skeleton</code>s.</li>
  <li><code class="language-plaintext highlighter-rouge">98 00 00 00</code>: that’s <code class="language-plaintext highlighter-rouge">152</code> in decimal, which happens to be exactly <code class="language-plaintext highlighter-rouge">38*4</code>! Don’t know what to do with that, though.</li>
  <li><code class="language-plaintext highlighter-rouge">FF FF FF FF FF FF FF FF</code>: two separators, yay.</li>
  <li>37 <code class="language-plaintext highlighter-rouge">int</code>s: <code class="language-plaintext highlighter-rouge">0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 8, 12, 3, 14, 3, 16, 17, 18, 19, 20, 21, 22, 20, 24, 0, 26, 27, 28, 29, 30, 31, 27, 33, 34, 35, 36</code>. It’s a list of integers going from 0 to 36, almost sorted, with some repetitions.</li>
  <li><code class="language-plaintext highlighter-rouge">00 01 00 03</code>: Same, no idea, is in all <code class="language-plaintext highlighter-rouge">.Skeleton</code>s.</li>
  <li><code class="language-plaintext highlighter-rouge">F0 05 00 00</code>: <code class="language-plaintext highlighter-rouge">1520</code> in decimal… <code class="language-plaintext highlighter-rouge">38*40</code>! So what?</li>
  <li><code class="language-plaintext highlighter-rouge">FF FF FF FF</code>: another separator.</li>
</ul>

<p>Now came the scary part: 1528 bytes (that’s <code class="language-plaintext highlighter-rouge">38*40 + 8</code>…) until the last 4, another separator. Again, if you are following on the image, that’s at line <code class="language-plaintext highlighter-rouge">000014E0</code>.</p>

<p><strong>I assumed there had to be at least 38 triplets of floats somewhere, to represent one vertex for each bone name found earlier, somehow.</strong> As 1528 is indeed divisible by 4, the size of a <code class="language-plaintext highlighter-rouge">float</code> (or <code class="language-plaintext highlighter-rouge">int</code>), I decided to break it down into 4-byte groups, and doing that, I noticed there were <strong>lots of triples of <code class="language-plaintext highlighter-rouge">00 00 80 3F</code></strong>. By looking at the character representations of the binary data back in the image, they can be easily spotted by the sequence <code class="language-plaintext highlighter-rouge">..Ç?..Ç?..Ç?</code>. With <a href="https://en.wikipedia.org/wiki/Endianness">endianness</a> in mind, <strong>it turns out that <code class="language-plaintext highlighter-rouge">0x3F800000</code> in <a href="https://en.wikipedia.org/wiki/IEEE_754">IEEE 754</a> is exactly <code class="language-plaintext highlighter-rouge">1.0</code></strong>! That left me confident I was on the right path.</p>

<p>Taking the 1528 bytes, ignoring the first 8 (<code class="language-plaintext highlighter-rouge">00 00 00 80 47 92 36 41</code>), and splitting the rest into 38 groups of 40 bytes (10 <code class="language-plaintext highlighter-rouge">float</code>s) each gave me a hunch to further split those 10 <code class="language-plaintext highlighter-rouge">float</code>s into groups of 1, 3, 3, and 3. Here’s a snippet of that, with prettier whitespace:</p>

<figure class="highlight"><pre><code class="language-plaintext" data-lang="plaintext">24 BF C2 BD
    00 00 80 3F   00 00 80 3F   00 00 80 3F
    00 00 00 00   00 00 00 00   00 00 00 00
    00 00 80 3F   00 00 00 80   CD BA 4B 41
26 33 E2 BD
    00 00 80 3F   00 00 80 3F   00 00 80 3F
    00 00 00 00   00 00 00 00   F2 04 35 BF
    F3 04 35 3F   93 14 36 A4   30 41 5E 41
EA 79 62 BE
    00 00 80 3F   00 00 80 3F   00 00 80 3F
    00 00 00 00   00 00 00 00   F2 04 35 BF
    F3 04 35 3F   25 5A 98 A4   45 F6 79 41
[...]
A2 4E 58 3F
    00 00 80 3F   00 00 80 3F   00 00 80 3F
    E6 3E 3D 3F   93 8D 0D 3C   48 5F 2C 3F
    D8 24 0F BC   51 E9 A7 3F   5D 82 9B 3E
E3 19 03 40
    00 00 80 3F   00 00 80 3F   00 00 80 3F
    D4 B3 7F 3F   AC 4F 49 3C   DB E6 3E BD
    A6 03 90 B8   00 03 00 03   00 00 00 00</code></pre></figure>

<p>Taking those <code class="language-plaintext highlighter-rouge">float</code>s and <a href="https://www.h-schmidt.net/FloatConverter/IEEE754.html">converting them into decimals</a> yields:</p>

<figure class="highlight"><pre><code class="language-plaintext" data-lang="plaintext">-0.09509
     1.000    1.000    1.000
     0.000    0.000    0.000
     1.000   -0.000   12.733
-0.11045
     1.000    1.000    1.000
     0.000    0.000   -0.707
     0.707   -0.000   13.891
-0.22117
     1.000    1.000    1.000
     0.000    0.000   -0.707
     0.707   -0.000   15.623
[...]
 0.84495
     1.000    1.000    1.000
     0.739    0.009    0.673
    -0.009    1.312    0.304
 2.04845
     1.000    1.000    1.000
     0.999    0.012   -0.047
    -0.000    0.000    0.000</code></pre></figure>

<p>Assuming they keep their order, <strong>each of the 38 bones has a name and 10 <code class="language-plaintext highlighter-rouge">float</code>s related to it</strong>. If I enumerated them from 0 through 9, for each of the groups of 10:</p>
<ul>
  <li>0: Unsure. Definitely a <code class="language-plaintext highlighter-rouge">float</code>, though.</li>
  <li>1, 2, 3: Unsure. In most of the <code class="language-plaintext highlighter-rouge">.Skeleton</code>s, all <code class="language-plaintext highlighter-rouge">1.0</code>s. Rarely, may have a slight (±0.2) variation.</li>
  <li>4, 5, 6: Unsure. In all of the <code class="language-plaintext highlighter-rouge">.Skeleton</code>s, are in the interval <code class="language-plaintext highlighter-rouge">[-1.0, 1.0]</code>.</li>
  <li>7, 8, 9: Those were all over the place. Looked like coordinates.</li>
</ul>

<p>Of course, I took the last three <code class="language-plaintext highlighter-rouge">float</code>s of each of the 38 groups and threw them into <a href="https://matplotlib.org/"><code class="language-plaintext highlighter-rouge">matplotlib</code></a> as if each of the triplets were a point in 3D space:</p>

<p><img src="/images/reverse-engineering-lunia/skeleton-1.png" alt="" /></p>

<p>Boom. I had something that looked like a humanoid figure.</p>

<p>Do keep in mind that this took a whole day of staring at a bunch of bytes, but the feeling when I finally had the plotted coordinates was so, so worth it. Well, I supposed the next steps were to “connect the dots”, right? I then watched some hours of Blender tutorials on rigging, to finally try and understand what armatures really were, and what I should be looking for.</p>

<p>Ideally, <strong>most of the bones should be interconnected</strong>, so when you move a shoulder, the arm moves as well, and so do the fingers. If you twist the waist, their whole upper body should move accordingly. <strong>That strongly suggested some kind of hierarchy, which instantly made me think of <a href="https://en.wikipedia.org/wiki/Tree_(data_structure)">trees</a>.</strong> The only data on the file that could possibly have something to do with hierarchies and tree structures were <strong>the sequence of almost sorted 37 <code class="language-plaintext highlighter-rouge">int</code>s</strong> located right after the bone names and the points.</p>

<p>However, having one fewer than the number of bones kinda threw me off for a good while. 
After more hours of staring at binary, I realized <strong>most of the bones were listed in an almost sorted order</strong>: <code class="language-plaintext highlighter-rouge">L_Shoulder</code>, <code class="language-plaintext highlighter-rouge">L_UpperArm</code>, <code class="language-plaintext highlighter-rouge">L_ForeArm</code>, <code class="language-plaintext highlighter-rouge">L_Wrist</code>, <code class="language-plaintext highlighter-rouge">L_Hand</code>, <code class="language-plaintext highlighter-rouge">L_Finger1</code>, <code class="language-plaintext highlighter-rouge">L_Finger2</code>, <code class="language-plaintext highlighter-rouge">L_Finger3</code>, <code class="language-plaintext highlighter-rouge">L_Thumb1</code>, <code class="language-plaintext highlighter-rouge">L_Thumb2</code>… All of that almost matched the number sequence in question, but putting both lists side by side didn’t make much sense, and neither did the names, until…</p>

<p>Until I realized <strong>there had to be a reference point for the whole model, a <code class="language-plaintext highlighter-rouge">Base</code></strong>. The trick was that, although its name was listed first, it was actually the last point in the file. With that fix, I could now properly match the points and names. Moreover, the sequence having one less element than the amount of bones probably meant there was none for the <code class="language-plaintext highlighter-rouge">Base</code> bone, which made everything fit.</p>

<p><strong>The number sequence was a <a href="https://en.wikipedia.org/wiki/Serialization">serialized</a> tree</strong>, with each integer representing the index of the parent bone, with <code class="language-plaintext highlighter-rouge">0</code> being the base (last bone). When I finally connected everyone to its parent…</p>

<video src="/images/reverse-engineering-lunia/skeleton-2.mp4" controls="" preload="metadata" loop="">
</video>

<p>I quickly wrote a Python script to load any <code class="language-plaintext highlighter-rouge">.Skeleton</code> and output their armature using what I had found so far. From experimenting with a bunch of other models, <strong>a couple of them seemed to be a little bit skewed, or with all of the points in the same plane, or with some other deformations, which probably indicates there’s data missing</strong>. Well, I guess it’s got something to do with all those other <code class="language-plaintext highlighter-rouge">float</code>s I completely ignored along the way.</p>

<p>Also, it was not that big of a surprise that <strong>all player characters had over a hundred bones each, complete with wing bones, skirt bones, weapon bones</strong>… Some of the main bosses also had more complex skeletons, and I then realized tackling the bank guy first was a great idea.</p>

<p>The <code class="language-plaintext highlighter-rouge">.SkinnedAnim</code>s were still left untouched, for now. I did take a look at them, but I still feel that completing my understanding of the <code class="language-plaintext highlighter-rouge">.Skeleton</code>s were a must before going further, so no advancements made there. Once more, I tried searching for answers and previous work online, when I stumbled upon…</p>

<h3 id="6-server-files-and-game-source-code">6. Server Files and Game Source Code</h3>

<p>I got my hands on a huge collection of files, along with tutorials on how to fire up a server, as well as the source code itself. I supposed all of that were leaked, somehow? This was mostly a general exploration, as an attempt to better understand the architecture and find the data tables and such.</p>

<p><strong>Lunia’s servers ran on <a href="https://en.wikipedia.org/wiki/Active_Server_Pages">ASP</a>, <a href="https://en.wikipedia.org/wiki/Internet_Information_Services">IIS</a>, and <a href="https://en.wikipedia.org/wiki/Microsoft_SQL_Server">MSSQL</a>, all on top of Windows Server 2003.</strong> It’s interesting to note that it appears each Town Square was a single server instance, and each chat channel was also an independent IRC-based server. As the technologies used were ancient compared to the ones available today, and most of the files I had were barely functional, I have to admit I wasn’t much interested in trying to set up my own server or investigating further. After snooping around for some minutes, I turned my attention to the real interesting stuff: the game source code and development files.</p>

<p><strong>Lunia itself was built on <a href="https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B">Visual C++</a></strong>, and seemed to have grown alongside its own custom engine, “XRated”. With it, there were dozens of custom tools to create and edit items, quests, pets, chests, and so on. A lot of code had the purpose of converting to and from those pesky custom file formats, and so they are probably very helpful for reverse engineering them.</p>

<p>All the “compiled” files found earlier in the client data could also be found here, like the <code class="language-plaintext highlighter-rouge">.tga</code> files that eventually generated all <code class="language-plaintext highlighter-rouge">.dds</code> 2D assets, all the <code class="language-plaintext highlighter-rouge">.xml</code> that eventually became the <code class="language-plaintext highlighter-rouge">.b</code> databases, and the uncompiled <code class="language-plaintext highlighter-rouge">.fx</code> shader code that were loaded in the client as compiled <code class="language-plaintext highlighter-rouge">.fxc</code>.</p>

<p>Here are the most interesting bits, and what I was actually looking for:</p>
<ul>
  <li>A conversion table for items, skills and characters, to a unique integer hash, used in all other files.</li>
  <li>All item stats and properties (e.g. is tradable, is usable, cooldowns, level requirements).</li>
  <li>Tables for all fortifications and their stats multipliers.</li>
  <li>Tables for fishing rods, drop rates and other variables.</li>
  <li>All quest data, requirements and rewards.</li>
  <li>All shops, items for sale, sales prices, etc.</li>
  <li>Skills and its requirements, damage, cooldowns, etc.</li>
</ul>

<p>I then grabbed most of the data tables and spent a day or two writing a dozen Python scripts to parse the <code class="language-plaintext highlighter-rouge">.xml</code>s and convert parts of them to <a href="https://en.wikipedia.org/wiki/JSON">JSON</a> objects, which I plan to use later with the Pygame application from before.</p>

<p>The code documentation was… rough, to say the least. Lots of comments were in Korean, and the code style in general was definitely inconsistent - I did find a <code class="language-plaintext highlighter-rouge">.txt</code> that listed some guidelines, though! I also found a comment in one of the files that handled the animations, which simply wrote “<a href="https://www.youtube.com/watch?v=I9AiyoKUJlU">banco de gaia - celestine</a>”. I wonder if that was the song whoever wrote that piece of code was listening to at the time?</p>

<p><img src="/images/reverse-engineering-lunia/source-code-1.png" alt="" /></p>

<p>Of course, <strong>there was also all the code for the graphics rendering</strong>, like the one above. Most of them were also authored by <code class="language-plaintext highlighter-rouge">juhnu</code>, the same name found earlier. I managed to find the code responsible for loading the 3D model files mentioned in the last section, and some of my assumptions were confirmed, while others were corrected.</p>

<ul>
  <li><strong>The last section of the <code class="language-plaintext highlighter-rouge">.SkinnedMesh</code> files are, per the code that handles it, “skin weights”.</strong> Not sure what to use them for, but oh well.</li>
  <li><code class="language-plaintext highlighter-rouge">.Skeleton</code>s are indeed composed of a header, a list of bone names, a bone hierarchy and a reference pose. <strong>A bone <code class="language-plaintext highlighter-rouge">struct</code> is composed of a <code class="language-plaintext highlighter-rouge">float3 position</code>, <code class="language-plaintext highlighter-rouge">float3 scale</code> and <code class="language-plaintext highlighter-rouge">floatquat orientation</code>.</strong> Could the latter be a <a href="https://www.youtube.com/watch?v=d4EgbgTm0Bg">quaternion</a>? Interesting…</li>
  <li><strong><code class="language-plaintext highlighter-rouge">.SkinnedAnim</code>s are made of starting and ending frames, a speed modifier, a list of frames, a list of bones, a frame interval and a frame rate.</strong> The animation code does give more hints on how to decompose the files.</li>
</ul>

<p><img src="/images/reverse-engineering-lunia/source-code-2.png" alt="" /></p>

<p>There’s still a ton of stuff for me to go through, and I feel all of this was just a glimpse of the whole codebase. With that…</p>

<h3 id="7-future-work">7. Future Work</h3>

<p>As I wrote in the beginning, I still want to take all of this a lot further, which may make an update here or even as a whole new post.</p>

<p>Regarding the <strong>Python Inventory / Window Manager thingy</strong>, here’s what I’m planning as the next steps:</p>

<ul>
  <li><strong>Item shops</strong>, buying and selling, and the currency itself (in-game screenshot below).</li>
  <li><strong>Item fortification</strong>, together with reagents and catalysts (<a href="/images/reverse-engineering-lunia/game-fortification.jpg">in-game screenshot</a>).</li>
  <li><strong>Stats calculations</strong> based on class, level and equipped items (<a href="/images/reverse-engineering-lunia/game-stats.jpg">in-game screenshot</a>).</li>
  <li><strong>Fishing</strong> and all of its mechanics.</li>
  <li><strong>Extract item data to an item server and API</strong>, so as to be able to have the whole item database accessible without having to load it all on every app startup, as well as to mimic more closely the original game.</li>
  <li><strong>A “wardrobe” tool / model viewer</strong>, based on the currently equipped items. However, that wouldn’t be possible in Pygame, which is strictly a 2D library, so I would have to rewrite all of it in something else like <a href="https://unity.com/">Unity</a>. That would be a whole new journey, once again starting from barely any experience, and I’m definitely looking forward to that.</li>
  <li>Overall tidying up of the code, and greater adherence to best OOP practices.</li>
</ul>

<p><img src="/images/reverse-engineering-lunia/game-shop.jpg" alt="" /></p>

<p>With regards to the <strong>3D assets</strong>, I may continue to work on them by:</p>

<ul>
  <li><strong>Figuring out the remaining data in the <code class="language-plaintext highlighter-rouge">.SkinnedMesh</code>, <code class="language-plaintext highlighter-rouge">.Skeleton</code> and <code class="language-plaintext highlighter-rouge">.SkinnedAnim</code> files</strong> and how to convert/export them to Blender.</li>
  <li>Further exploration of Blender, 3D animation and modeling/rigging - maybe even <strong>rendering short animations based on Lunia’s models</strong> if my creativity and artsy skills allow.</li>
  <li><strong>3D printing</strong> characters to create small figures - if I manage to get access to a 3D printer.</li>
</ul>

<p>At last, about the <strong>server files and source code</strong>:</p>

<ul>
  <li>Finish opening and reading every single file and see what else I can find, as well as what logic I can replicate.</li>
</ul>

<p>And… whatever else might pop in my head during all of that.</p>

<h3 id="8-closing-thoughts">8. Closing Thoughts</h3>

<p>It’s quite interesting to note how much software development has changed over the last 10 or 15 years. As I could notice by the server files and source code, there were barely any design patterns or previous work done on MMORPGs and game engines back then, as most of the filetypes, encodings and tools were homemade and custom to Lunia.</p>

<p>Furthermore, I don’t think I’ve previously worked on anything that mashed together so many different areas and technologies like this. Trying to reverse engineer as much as I can from Lunia has been a great learning experience, including regarding topics I never thought I would be interested in. It’s been a fantastic (and fun!) couple weeks, and I hope to have the spare time to keep exploring all of this for a while.</p>

<p>To wrap it up, <strong>shout out to <a href="https://github.com/renatavinhaga">@renatavinhaga</a>, <a href="https://github.com/mbrla0">@mbrla0</a> and <a href="https://github.com/gosiqueira">@gosiqueira</a> for being extremely helpful in this whole endeavor</strong>. Finally, <strong>a big and heartfelt thank you to everyone involved in the making of Lunia</strong>. It definitely played a big role in my youth and in shaping me into who I am today, personality and career-wise. You are all my childhood superheroes.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Lunia was an MMORPG by South Korean producer allm, originally launched in early 2006 and published in Brazil by Level Up! Games in late 2008. Its main premise was being an MMORPG with heavy elements of an arcade beat ‘em up, being one of the first to combine both genres. I started playing Lunia sometime in 2009, and it was what taught me fast typing, introduced me to online forums and communities, and gracefully presented me the world of MMOs in general. The game was the biggest time-sink of young me until late 2012, when the Brazilian servers shut down. Sadly, the global servers followed suit just a year after. It’s fair to say it was far from being the largest MMO at the time, but to 9-year-old me, it was golden. Recently, I stumbled upon some screenshots buried deep in my file archives. After a couple days of reminiscing old times in some unofficial servers that are still around - and realizing the game aged surprisingly well (although it might be just my nostalgia talking) - I decided to use the skills that I acquired since then to snoop around the game files, maybe learning some cool stuff along the way. As it turns out, that was quite successful and exceedingly fun, so here’s a quite lengthy rundown of my journey. I probably spent over 150 hours in the last month to get up to this point, and it is still very much a work in progress. Many of the game files are still hidden or unexplored, and there’s a bunch that I still plan to do with the extracted assets. With that, I may update this post (or write follow-ups) in the near future if I do so.]]></summary></entry><entry><title type="html">Games for Programmers (and Learners)</title><link href="https://www.maiakanegae.com/games-for-programmers-and-learners/" rel="alternate" type="text/html" title="Games for Programmers (and Learners)" /><published>2020-05-05T00:00:00+00:00</published><updated>2020-05-05T00:00:00+00:00</updated><id>https://www.maiakanegae.com/games-for-programmers-and-learners</id><content type="html" xml:base="https://www.maiakanegae.com/games-for-programmers-and-learners/"><![CDATA[<p><img src="/images/games-for-programmers-and-learners/header.jpg" alt="" /></p>

<p>Games taught me all sorts of things: time management, fast typing, interpersonal skills, dealing with money and economy in general, and even how to read and write. Since I found out how exciting coding was, I turned my attention to the ones that can actually teach programming - and are still fun. Turns out solving puzzles using a made-up programming language inside a video game is as satisfying as solving a real coding challenge in a real environment, and best of all: the skills are transferable!</p>

<p>Compiled here is a list of my favorite programming games alongside a mini-review, in no specific order, for those who code - or would like to learn.</p>

<!--more-->
<hr />

<h3 id="human-resource-machine-and-7-billion-humans"><a href="https://store.steampowered.com/app/375820/">Human Resource Machine</a> and <a href="https://store.steampowered.com/app/792100/">7 Billion Humans</a></h3>

<p>From <a href="https://tomorrowcorporation.com/">Tomorrow Corporation</a>, the creators of <a href="https://store.steampowered.com/app/22000/">World of Goo</a> and <a href="https://store.steampowered.com/app/221260/">Little Inferno</a> - which although far from being about coding are very much worth checking out -, comes <strong>Human Resource Machine</strong> and its sequel, <strong>7 Billion Humans</strong>.</p>

<p>In <strong>Human Resource Machine, you control office workers that pick up and drop off little green boxes with data on them.</strong> To make them do stuff, you write Assembly programs (with cute blocks and graphics), with every level teaching you new tricks and giving you more toys to play with. It does start pretty basic, but later levels can pack quite a punch. Oh, and you name your variables by scribbling on a post-it note, and comments work in the same way.</p>

<div style="width: ; margin: 0 auto;">

    <div class="ytcontainer">
        <iframe class="yt" src="https://www.youtube.com/embed/428R_oEjGGI" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
    </div>
</div>

<p>The big change for the sequel? More people! You now have to command your own swarm of workers, as if you were programming a parallel computer! Naturally, there’s also a bunch of new functions and triggers for added complexity and fun.</p>

<div style="width: ; margin: 0 auto;">

    <div class="ytcontainer">
        <iframe class="yt" src="https://www.youtube.com/embed/Wo8gePOdv-k" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
    </div>
</div>

<p>The art style follows the same recipe as the other games from Tomorrow Corporation, as does the humor, both on point. The soundtrack does its job, but it can get repeating after a couple hours of play. Overall, <strong>Human Resource Machine</strong> and <strong>7 Billion Humans</strong> are a great starting point for anyone learning or practicing programming logic, no matter the age or skill level.</p>

<h3 id="zachtronics-games"><a href="http://www.zachtronics.com/">Zachtronics</a> Games</h3>

<p>Any list of programming games has to contain at least one of Zachtronics’ amazing titles. I do encourage you to check out all of them, but I’ll be listing my two favorite ones here. Probably the most “serious” games on this list coding-wise, most of them require you to actually study - PDF manuals in the game files detailing some computer architecture and its language syntax - so you are able to progress through the first level, and later ones can be a challenge to even veteran programmers. They all mostly follow the same recipe, with some spice added to it: learn a new Assembly language; write programs with it that do cool stuff; optimize it as much as you feel like it; share your solution with friends. Also, <a href="http://www.readthefuckingmanual.com/">RTFM</a>.</p>

<p><strong><a href="https://store.steampowered.com/app/716490/">Exapunks</a> is about hacking stuff to earn money so you’re able to buy medicine and survive.</strong> You write code to control EXecution Agents, the EXAs: small robots that are able to get into networks - and even your own body -, and fulfill contracts to “improve” candy production from the nearby factory, change someone’s bank account balance or hijack a highway digital billboard to show neat stuff. Be ready to dive deep into magazines from the 90’s detailing secret functionalities and specific language syntax. Arguably the easiest of the Zachtronics collection, so a great one to start with.</p>

<div style="width: ; margin: 0 auto;">

    <div class="ytcontainer">
        <iframe class="yt" src="https://www.youtube.com/embed/_rOIUUVFRKc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
    </div>
</div>

<p><strong><a href="https://store.steampowered.com/app/370360/">TIS-100</a> tasks you with powering up your deceased uncle’s old computer</strong>, the Tesselated Intelligence System, a “massively parallel computer architecture comprised of non-uniformly interconnected heterogeneous nodes”. Fancy. Write small snippets of Assembly code into separate CPUs that are able to communicate only with the ones adjacent to it. Learn about blocking and non-blocking operations and many other parallel programming quirks, and figure out the machine’s secrets while you’re at it.</p>

<div style="width: ; margin: 0 auto;">

    <div class="ytcontainer">
        <iframe class="yt" src="https://www.youtube.com/embed/ZkUHGvy2pNU" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
    </div>
</div>

<h3 id="hacknet"><a href="https://store.steampowered.com/app/365450/">Hacknet</a></h3>

<p>A spiritual successor to 2001’s <a href="https://store.steampowered.com/app/1510/">Uplink</a>, <strong>Hacknet is at its core a hacking simulator</strong>. Of course, it’s quite far from the reality of real pentesters and infosec experts, but it does have some roots on real UNIX commands, ports, firewalls and networks.</p>

<div style="width: ; margin: 0 auto;">

    <div class="ytcontainer">
        <iframe class="yt" src="https://www.youtube.com/embed/A-jN16bNPhk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
    </div>
</div>

<p>You won’t learn much real programming here, but the amazing atmosphere, deep immersion and great storytelling are all there, supported by <strong><a href="https://bossbattlerecords.bandcamp.com/album/hacknet">the greatest soundtrack</a> across all games on this list</strong> - it’s on <a href="https://open.spotify.com/album/6vKaTpEfIxe39EkoGlUv9i">Spotify</a> as well! Moral dilemmas, secret organizations and cool graphics are all just icing on the cake.</p>

<p>Hacknet’s main storyline can be played from start to finish in around 5 or 6 hours, and my recommendation is to free up a night in your schedule to go through the whole experience in a single session. It’s been 3 years since I have done exactly that, and I still get chills when listening to the <a href="https://www.youtube.com/watch?v=qFfybn_W8Ak">last mission’s theme</a>.</p>

<h3 id="factorio"><a href="https://store.steampowered.com/app/427520/">Factorio</a></h3>

<p>The best way to describe this game in one sentence is that it is the closest thing humankind got to a time machine. See, it’s Sunday night, you just had dinner, bought the game, played for what looked like 40 minutes and suddenly the sun is up, class started an hour ago, your friends are calling to check on your whereabouts and Steam says you’ve been playing for over 10 hours straight. No, of course that wasn’t me, why do you ask?</p>

<p><strong>Factorio is a game about automation and logistics.</strong> Start small, stranded in a foreign planet with not much more than a pickaxe, a gun, and determination to build a rocket and launch a satellite. Then, craft resources by hand and build machines that can do the crafting for you. Design factories with increasingly complex parts and recipes, avoiding bottlenecks and maximizing output, all while controlling power consumption and protecting your base from alien attacks. Also, nuclear power. Also, <a href="https://www.youtube.com/watch?v=hHkKJfcBXcw">trains</a>.</p>

<div style="width: ; margin: 0 auto;">

    <div class="ytcontainer">
        <iframe class="yt" src="https://www.youtube.com/embed/J8SBp4SyvLc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
    </div>
</div>

<p>So, where’s the coding? Factorio’s <a href="https://wiki.factorio.com/Circuit_network">circuit network</a> is Turing complete, much like Minecraft’s classic redstone mechanics, and people are able to do <a href="https://www.youtube.com/watch?v=7lVAFcDX4eM">crazy stuff</a> with it, but that’s not the reason for its inclusion on this list. The main game mechanic and goals have a lot in common with real-world programming: you have to plan before you build (code?), and you better modularize it. Otherwise, technical (construction?) debt is real - although, surprisingly enough, tearing down all the work done in the past few hours and rebuilding it, now bigger and better, is way more fun than it sounds. Not coincidentally, the intersection between Factorio players and programmers is fairly big.</p>

<p>As you may imagine, the learning curve is pretty steep (isn’t that true for most of the games here, though?), but learning the basics by yourself instead of watching a bunch of tutorials is absolutely worth it. Once you get into the “just one more thing and I’m done” loop, you’re set.</p>

<p>The game is still in Early Access <strong>(Update Aug. 14, 2020: Not anymore! Trailer above updated as well.)</strong>, but don’t be fooled by it: Factorio is one of those rare exceptions where that is a big plus instead of an excuse. Also, the dev team maintains a <a href="https://factorio.com/blog/">development blog</a> with weekly updates, often diving deep into technical details. A favorite of mine is <a href="https://factorio.com/blog/post/fff-317">FFF #317</a>, which explains in detail the enemies’ pathfinding algorithm.</p>

<p>You have been warned: it’s crazy addicting, and the replayability is insane. The factory must grow.</p>

<h3 id="satisfactory"><a href="https://store.steampowered.com/agecheck/app/526870/">Satisfactory</a></h3>

<p>Being the most recent title in this list, <strong>Satisfactory is, in a nutshell, a 3D Factorio</strong>. Still in Early Access (like, real early) and so it lacks many features that would make it deep, but the environments, buildings and creatures are gorgeous and the developer’s community engagement is great. As it’s 3D, it does require a beefier computer than any other game listed here, limiting the factory complexity to a way lower degree compared to Factorio (unless you are <a href="https://www.youtube.com/watch?v=Oh2oF-eZTD8">this guy</a>). Satisfactory is already a beautiful and fun game and does look very promising. I will be sure to take a second look at it in a few updates.</p>

<div style="width: ; margin: 0 auto;">

    <div class="ytcontainer">
        <iframe class="yt" src="https://www.youtube.com/embed/QvWaV4qshZQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
    </div>
</div>

<h3 id="programming-games-backlog">Programming Games Backlog</h3>

<p>Those are the ones that I haven’t immersed myself in enough yet to write a paragraph of opinion about it, but are right at the top of my big backlog of games that I want to get through. They are full of positive reviews all around the internet and so I felt like listing them here as well.</p>

<p><strong><a href="https://store.steampowered.com/app/400110/">Else Heart.Break()</a></strong>: a mix of RPG, open-world and point-and-click adventure, with a story of love and friendship behind the programming curtain.</p>

<p><strong><a href="https://store.steampowered.com/app/736260/">Baba is You</a></strong>: a game about logic and thinking outside the box. Not sure why, but it does tickle my fancy in the same way coding does.</p>

<p><strong><a href="https://store.steampowered.com/app/558990/">Opus Magnum</a></strong>, <strong><a href="https://store.steampowered.com/app/504210/">SHENZHEN I/O</a></strong> and <strong><a href="https://store.steampowered.com/app/92800/">SpaceChem</a></strong>: of course, more Zachtronics titles that I’m looking forward to checking out. More of the same I guess, but in different flavors.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Games taught me all sorts of things: time management, fast typing, interpersonal skills, dealing with money and economy in general, and even how to read and write. Since I found out how exciting coding was, I turned my attention to the ones that can actually teach programming - and are still fun. Turns out solving puzzles using a made-up programming language inside a video game is as satisfying as solving a real coding challenge in a real environment, and best of all: the skills are transferable! Compiled here is a list of my favorite programming games alongside a mini-review, in no specific order, for those who code - or would like to learn.]]></summary></entry><entry><title type="html">Advent of Code 2019 in Review</title><link href="https://www.maiakanegae.com/advent-of-code-2019-in-review/" rel="alternate" type="text/html" title="Advent of Code 2019 in Review" /><published>2019-12-27T00:00:00+00:00</published><updated>2019-12-27T00:00:00+00:00</updated><id>https://www.maiakanegae.com/advent-of-code-2019-in-review</id><content type="html" xml:base="https://www.maiakanegae.com/advent-of-code-2019-in-review/"><![CDATA[<p><img src="/images/advent-of-code-2019-in-review/header.png" alt="" /></p>

<p>At last, <strong><a href="https://adventofcode.com/2019">Advent of Code 2019</a></strong> has come to an end! If you are new to it, it’s an Advent calendar full of programming puzzles from December 1st all the way to Christmas, made by the amazing <a href="http://was.tl/">Eric Wastl</a> every year since 2015.</p>

<p>This was my second year participating, but the first time actually completing all days before the end of the month! You can check my <strong>Python 3</strong> solutions on my <strong><a href="https://github.com/maiakanegae/advent-of-code">GitHub</a></strong>, and you can also <strong>keep reading for more info and my comments on the event.</strong></p>

<!--more-->
<hr />

<p>Other than being a collection of 50 very fun programming puzzles (each day has two parts!), Advent of Code is also a <a href="https://adventofcode.com/2019/leaderboard">competition</a>, but <a href="https://www.reddit.com/r/adventofcode/comments/e2wjhf/tips_for_getting_on_the_advent_of_code_leaderboard/f90ksek/">only if you want it to be</a>. And, way more importantly than that, it’s a mission for you to save Christmas! This year, <strong>“Santa has become stranded at the edge of the Solar System while delivering presents to other planets!”</strong>, and so every puzzle is space-themed! Neat!</p>

<p>The 2019 edition of the event also had a brand new twist: usually, there are only a couple of puzzles that rely on the solution of a previous one. This time, almost half of them did! Starting at Day 2 and revisiting it every other day from Day 5 onwards, we were tasked with <strong>building an Intcode computer</strong>: in other words, <strong>creating a Virtual Machine to run machine code from a very specific architecture description</strong>, much similar to the <a href="/synacor-challenge-in-review/">Synacor Challenge</a>. I was introduced to low-level programming at my Computer Organization and Computer Architecture courses, and I’ve since loved doing these! Indeed, that was the highlight of this year for me, by far.</p>

<p>Of course, another big highlight was me actually managing to get some sweet leaderboard points! As puzzles unlock at midnight EST/UTC-5, aka 2AM my local time, it wasn’t always feasible to be up and ready to compete. However, <strong>I did get a total of 351 points, placing me at <a href="https://betaveros.github.io/extra-aoc-stats/">196th on the Global Leaderboard</a>!</strong> Although definitely far from the top 100, I’m more than excited about it.</p>

<p>All in all, <strong>I had an amazing time with it and I highly recommend it to anyone looking to learn or practice programming and problem solving.</strong> Now, to fill the void it left on me, I have to go back and complete all previous years…</p>

<h3 id="notable-comments">Notable Comments</h3>

<p><strong><a href="https://adventofcode.com/2019/day/1">Day 1</a>:</strong> Leaderboard get! The first day has always been a very simple problem to introduce newcomers to the event format and answer submission, this year being a twist on “sum all numbers of a list”. By hastily skimming through the problem statement and having my boilerplate code ready, I managed to finish Part 1 in just 46 seconds!</p>

<p><strong><a href="https://adventofcode.com/2019/day/6">Day 6</a>:</strong> Basic knowledge of trees required. Part 2 was a nice refresher on the classic Lowest Common Ancestor problem.</p>

<p><strong><a href="https://adventofcode.com/2019/day/7">Day 7</a>:</strong> This was when I noticed that I should probably modularize away my Intcode computer into its own class (eventually it evolved to being its own file). Great decision, by the way.</p>

<p><strong><a href="https://adventofcode.com/2019/day/10">Day 10</a>:</strong> Tough. Trigonometry galore. After a few hours of brainstorming, I had to resort to some tips from other people’s solutions. It was only after <a href="https://www.reddit.com/r/adventofcode/comments/e8m1z3/2019_day_10_solutions/fadhbo2/">doodling a bunch and explaining it to other people</a> that I fully understood what was going on. Much needed refresher on trig, though!</p>

<p><strong><a href="https://adventofcode.com/2019/day/11">Day 11</a>:</strong> Took me a bit to understand what I was actually supposed to do, but other than that it was a simple puzzle to exemplify the usage of the Intcode program as a <a href="https://en.wikipedia.org/wiki/Black_box">Black Box</a>. Instead, one could also <a href="https://www.reddit.com/r/adventofcode/comments/e9lxtv/2019_day_11_excel_cred_to_the_creators_of_aoc/">reverse-engineer it using Excel</a>.</p>

<p><strong><a href="https://adventofcode.com/2019/day/12">Day 12</a>:</strong> Another math-based puzzle, requiring some thinking to find the optimization trick for Part 2.</p>

<p><strong><a href="https://adventofcode.com/2019/day/13">Day 13</a>:</strong> So. Much. Fun! Definitely my favorite one of the year. Sadly, I missed Part 1’s leaderboard by mistyping the answer and being hit by the one-minute timeout. Always copy and paste, people!</p>

<p><strong><a href="https://adventofcode.com/2019/day/14">Day 14</a>:</strong> Many <a href="https://store.steampowered.com/app/427520/Factorio/">Factorio</a> vibes. This one threw me off a lot by having to take into account the leftovers, but I eventually found my way through.</p>

<p><strong><a href="https://adventofcode.com/2019/day/16">Day 16</a>:</strong> Arguably another math puzzle? Maybe half math and half programming. My original code for Part 1 took around two minutes, so Part 2 would finish computing in a couple thousand years! Of course, I had other things to do in that meantime so I ended up getting the trick for Part 2 from the subreddit. Reverse partial sum it was!</p>

<p><strong><a href="https://adventofcode.com/2019/day/17">Day 17</a>:</strong> Leaderboard get once again! For Part 2, I winged it and figured it was <a href="https://twitter.com/sophiebits/status/1206816590613733376">faster to do it by hand</a> than figuring out a compression algorithm on the fly. Apparently that was the better choice, as I got top 5! Of course, I later figured out the general solution for it.</p>

<p><strong><a href="https://adventofcode.com/2019/day/18">Day 18</a>:</strong> Pathfinding again, turned up to eleven. After hours of thinking and a couple tips later, my initial solution got me the right answer with a couple minutes of computing. Some <a href="https://github.com/maiakanegae/advent-of-code/commit/63d3d61d9126f7fe7aefcfc51500d3cb5c5f7ea3">really fun</a> <a href="https://github.com/maiakanegae/advent-of-code/commit/960efc07f17e100d49b5f534e167f658e5c33633">optimization rounds</a> later, I brought my solution down to a reasonable runtime.</p>

<p><strong><a href="https://adventofcode.com/2019/day/22">Day 22</a>:</strong> The mother of all math puzzles for this year. Heavy usage of modular arithmetic and number theory. The only day in the event that social life did not allow me to finish it in under 24 hours of it being released. I had to go through so much theory and so many explanations and breakdowns to understand it all that I feel like I learned more with it than in my whole Discrete Mathematics course.</p>

<p><strong><a href="https://adventofcode.com/2019/day/24">Day 24</a>:</strong> Finally, a cellular automaton! I loved those last year, and at this point I was worried they wouldn’t be making an appearance this time around. It did take me a while to wrap my head around Part 2’s problem statement, but I guess that’s just the nature of recursiveness!</p>

<p><strong><a href="https://adventofcode.com/2019/day/25">Day 25</a>:</strong> I’ve <a href="https://www.reddit.com/r/adventofcode/comments/e9zgse/2019_day_13_solutions/fan36t2/">waited so long for this</a>! I spent more than a few minutes misunderstanding the “lighter” and “heavier” terms and swapping them in my mind, and as a result I kept looking for more items. After I finally got over that, I wrote a quick and dirty bruteforce, so the solution was reached half manually and half automated. Once again, of course I did code the general solution afterwards. Second favorite, mainly because of <a href="https://github.com/maiakanegae/advent-of-code/commit/d6336e55cd4bafbf733fcbc77f13b6a28fbd2270">more fun rounds</a> of <a href="https://github.com/maiakanegae/advent-of-code/commit/4b2174948ceead8178c0b34c0afe962cc57e71ea">runtime optimization</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[At last, Advent of Code 2019 has come to an end! If you are new to it, it’s an Advent calendar full of programming puzzles from December 1st all the way to Christmas, made by the amazing Eric Wastl every year since 2015. This was my second year participating, but the first time actually completing all days before the end of the month! You can check my Python 3 solutions on my GitHub, and you can also keep reading for more info and my comments on the event.]]></summary></entry><entry><title type="html">Synacor Challenge in Review</title><link href="https://www.maiakanegae.com/synacor-challenge-in-review/" rel="alternate" type="text/html" title="Synacor Challenge in Review" /><published>2019-10-05T00:00:00+00:00</published><updated>2019-10-05T00:00:00+00:00</updated><id>https://www.maiakanegae.com/synacor-challenge-in-review</id><content type="html" xml:base="https://www.maiakanegae.com/synacor-challenge-in-review/"><![CDATA[<p><img src="/images/synacor-challenge-in-review/header.jpg" alt="" /></p>

<p>I’ve had the <strong><a href="https://challenge.synacor.com/">Synacor Challenge</a></strong> bookmarked for a couple years now, having probably found it somewhere on the <a href="https://adventofcode.com">Advent of Code website</a> or <a href="https://www.reddit.com/r/adventofcode/">subreddit</a>. Since I’m currently taking a Computer Architecture course and I’ve been busy for the last couple days building a <a href="https://github.com/maiakanegae/mips-pipeline-simulator">MIPS Pipeline Simulator</a> for it, I figured I would give it a shot.</p>

<p>It started just as a way to spend some free time I had on a friday morning, but as I started unraveling the challenge’s surprises, that quickly grew to a whole weekend spent solely on it. All my code is on my <strong><a href="https://github.com/maiakanegae/synacor-challenge">GitHub</a></strong>, as well as a full <a href="https://github.com/maiakanegae/synacor-challenge/blob/master/writeup.md">writeup</a>, written as I was progressing through the challenge. You can also <strong>keep reading for more info and my spoiler-free comments on it</strong>.</p>

<!--more-->
<hr />

<p>According to the description on the challenge website, it was given by <a href="https://www.synacor.com/">Synacor</a> at some tech conferences in 2016, and although it doesn’t award anything anymore, it’s still available for whoever wants to try it.</p>

<p>In a nutshell, your task is to <strong>write a Virtual Machine capable of executing an included binary file, according to the complete architecture description provided</strong>, getting eight passwords along the way. As you progress, more and more puzzles are thrown your way, and you are totally free to solve them however you like with whatever programming language - for some of them, pen and paper even.</p>

<p>The challenge is not easy by any means. It feels tailored for the Computer Science undergrad curriculum, as each step of the way covers the content of a different course I’ve taken. With that said, if you feel somewhat confident in your general CS abilities (do note I didn’t say “programming” only), <strong>I highly recommend that you go in blind.</strong> But, be aware that there are some hard barriers, in which you either get the solution instantly or you don’t - and it’s going to take you some hours of research or days of shower thoughts. <strong>The moment it all clicks, though: it’s glorious</strong>.</p>

<hr />

<p>Once again, <strong>remember to take a look at my <a href="https://github.com/maiakanegae/synacor-challenge/blob/master/writeup.md">writeup</a> after you’ve given the challenge a try</strong>, and see where our solutions differ! But do be aware though, that it spoils the entire thing!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I’ve had the Synacor Challenge bookmarked for a couple years now, having probably found it somewhere on the Advent of Code website or subreddit. Since I’m currently taking a Computer Architecture course and I’ve been busy for the last couple days building a MIPS Pipeline Simulator for it, I figured I would give it a shot. It started just as a way to spend some free time I had on a friday morning, but as I started unraveling the challenge’s surprises, that quickly grew to a whole weekend spent solely on it. All my code is on my GitHub, as well as a full writeup, written as I was progressing through the challenge. You can also keep reading for more info and my spoiler-free comments on it.]]></summary></entry></feed>