Porting c0.0.13a to Rust: The Trivial Update
In which the names come back, nothing changes, and we learn what “same game, different JAR” means for a porting project.
This is version 8 of 878. The code did not change. The blog post still needs to explain why.
The Shape of This Version
c0.0.13a, released May 30, 2009, is the deobfuscated twin of c0.0.13a_03. Same water. Same lava. Same bedrock. Same terrain generation. Same GUI system. Same rendering. Same physics. Same everything — except the class files inside the JAR now have human-readable names instead of ProGuard-mangled single letters.
Where c0.0.13a_03 gave us a.class through z.class and forced us to reconstruct intent from structure, c0.0.13a gives us CalmLiquidTile.class, LiquidTile.class, ImprovedNoise.class, Distort.class, Emboss.class, Synth.class. The detective work is unnecessary. The source code tells you what it does.
The file count increased from 44 to 52. The line count increased from 4,699 to 4,927. But these numbers reflect organizational changes — classes split out from inlined code, data classes given their own files, noise synthesis primitives extracted into a class hierarchy — not new features. The game produces the same output. It renders the same frames. It responds to the same inputs. If you played both versions blindfolded (or, more accurately, without looking at the window title), you could not distinguish them.
For the Rust port, this means something unusual: no code changes are required. The port of c0.0.13a_03 is already the port of c0.0.13a. What remains is asset extraction, version metadata, and the question of what, exactly, a porting blog post should discuss when there is nothing to port.
The Port: Title and Assets
The concrete changes for this version are minimal enough to enumerate completely:
Window title. The game window title updates to reflect the current version. This is a string constant change — the window that previously identified itself as c0.0.13a_03 now identifies as c0.0.13a. In practical terms, this is one line in main.rs where the window title is set. The change is cosmetic but important for version tracking: when we run the game, the title bar confirms which version we believe we are running.
Asset extraction. The client JAR for c0.0.13a contains the same texture atlas (terrain.png), the same individual texture files (dirt.png, grass.png, rock.png, water.png), the same character set image, and the same default level. These assets are extracted to assets/c0.0.13a/ following the project convention. The textures are byte-identical to the c0.0.13a_03 assets. We extract them anyway because each version maintains its own asset directory — the convention exists so that future versions with modified textures have a clean separation from earlier versions.
JAR preservation. The original client JAR is copied to jars/c0.0.13a/ for future comparison testing. This follows the project convention of preserving every original JAR, even when the version is functionally identical to its predecessor. The JAR is the primary source artifact. Everything else — decompiled source, extracted assets, analysis notes — is derived from it.
That is the complete list of changes. No Rust code was modified. No tests were added. No rendering paths were updated. No block types were changed. No physics constants were adjusted.
Why No Code Changes
This deserves explanation, because “no code changes” is not the default outcome when a new Minecraft version appears.
Every previous version in this project introduced at least one new feature that required Rust code changes. rd-132328 added the timer system. rd-20090515 added entities and particles. rd-160052 restructured tile properties. rd-161348 expanded the block palette. c0.0.11a added the HUD and font rendering. c0.0.13a_03 added liquids, bedrock, and fog. Each version required new Rust code to match new Java behavior.
c0.0.13a breaks the pattern because it is not, in any meaningful sense, a new version. It is a rebuild of the same source code with different compiler settings. The Java source that produced c0.0.13a_03’s obfuscated bytecode is the same Java source that produced c0.0.13a’s readable bytecode. The compiler generated the same instructions. ProGuard either ran (c0.0.13a_03) or did not (c0.0.13a). The output binary behaves identically.
Our Rust port targets behavior, not source structure. We do not port Java class hierarchies — we port what the game does. Since what the game does has not changed, the port has not changed. The LiquidTile / CalmLiquidTile class hierarchy in c0.0.13a maps to the same tile property functions we already implemented. The Distort / Emboss / Scale / Rotate / Synth noise classes map to the same terrain generation code we already wrote. The Coord, User, and LevelLoaderListener data classes map to functionality that is either already present or already deferred.
The test suite confirms this. All 97 tests pass without modification. The tests verify behavioral parity — block IDs, tile properties, terrain generation, liquid rendering parameters — and every behavior they test is unchanged. The tests do not care whether the Java source says CalmLiquidTile or q. They care that still water is block ID 9, that it uses texture index 14, that it is not solid, and that it renders with a lowered top face. All of these things remain true.
What the Deobfuscated Source Confirms
While no code changes were needed, the readable source code provides valuable validation of work done during the c0.0.13a_03 analysis. Every name we reconstructed through structural analysis can now be checked against the authoritative names.
Liquid tile hierarchy. We identified two behavioral modes for liquid blocks during deobfuscation: “flowing” (spreads to neighbors on tick) and “still” (settled, no updates needed). The deobfuscated source confirms this with LiquidTile (the base/flowing variant) and CalmLiquidTile (the settled variant). Our terminology was “flowing” and “still”; Notch’s terminology was “liquid” and “calm liquid.” The concepts are identical. Our deobfuscation was correct.
Noise functions. We identified three noise classes in c0.0.13a_03: one implementing Perlin’s improved noise algorithm, one summing octaves, and one composing two noise functions via domain warping. The deobfuscated source reveals a richer picture: five noise classes (Distort, Emboss, Rotate, Scale, Synth) forming a composable noise synthesis framework. The three classes we identified are correct — ImprovedNoise for Perlin’s algorithm, OctaveNoise for octave summation, and Distort for domain warping (what we called CombinedNoise). The two we missed (Emboss and Rotate) were either inlined by ProGuard or overlooked during structural analysis. Neither affects the terrain output — the terrain generator uses Distort and Scale as its primary composition tools. Emboss and Rotate may be unused in this version’s terrain generator, present as library code for future use.
Data classes. Three small classes (Coord, User, LevelLoaderListener) appear that we did not identify as distinct classes in the obfuscated version. These are data holders and interfaces that ProGuard likely inlined into their consumers. Coord is a coordinate triple. User is a username holder for the server save system. LevelLoaderListener is a callback interface for asynchronous level loading. None of these affect gameplay behavior. Their existence in the deobfuscated source confirms that the obfuscated version contained the same functionality in a different structural form.
The validation is reassuring. Our deobfuscation of c0.0.13a_03 was accurate in every respect that matters for the port. We identified the correct classes, attributed the correct behaviors, and implemented the correct functionality. The readable source confirms this without contradiction.
The Deobfuscation Workflow, Retrospectively
With c0.0.13a in hand, we can evaluate the deobfuscation workflow we developed for c0.0.13a_03.
The workflow was: identify the entry point, trace the dependency graph, match class signatures to known classes from previous versions, verify by behavior. This produced correct results. Every class we needed for the port was correctly identified. Every method we needed to understand was correctly interpreted. The port works, the tests pass, and the deobfuscated source confirms our analysis.
But the workflow was expensive. The deobfuscation of c0.0.13a_03 took longer than the analysis of any previous version, despite the underlying code being only incrementally more complex than c0.0.11a. The overhead was entirely in the name reconstruction — tracing a.a(b, c, d) to understand that it means level.setTile(x, y, z, blockId) is slow, tedious, and error-prone work that contributes nothing to understanding the algorithm. The algorithm is the same whether the method is called setTile or a. The obfuscation is a barrier to reading, not a barrier to understanding, but the reading is a prerequisite to the understanding.
The question for future versions: will they be obfuscated or readable? c0.0.13a suggests that obfuscation was not a permanent decision. Perhaps future versions will alternate. Perhaps the obfuscation returns permanently in a later alpha or beta. Either way, the workflow exists and is validated. If the next version is obfuscated, we apply the same process. If it is readable, we save the time.
The broader lesson is about the relationship between naming and comprehension. Code with good names is faster to read, but the reading speed is not the primary benefit. The primary benefit is that good names prevent misunderstanding. When a class is called CalmLiquidTile, you know what it does before you read a single line of its implementation. When a class is called q, you must read every line, trace every reference, and reconstruct the intent from behavior. The risk of misunderstanding is higher, and misunderstandings compound: if you misidentify class q, every analysis that references q is wrong.
We did not misidentify any classes in c0.0.13a_03. But we easily could have. The deobfuscated source is a safety net we did not know we had.
Test Suite: 97 Tests, Unchanged
All 97 tests pass. No new tests were added because no new behavior was introduced.
The test breakdown remains:
- Tile IDs and properties: Block IDs 0-11, solidity, opacity, liquid detection, liquid type classification.
- Textures: Texture indices for all block types including liquids and bedrock.
- Terrain generation: Water presence, bedrock floor, flat level isolation.
- Player physics: Movement, collision, gravity, jumping.
- Level operations: Block storage, lighting, serialization.
- Rendering parameters: Liquid top face height, brightness multipliers, face culling logic.
The tests verify behavior. The behavior has not changed. The tests pass. This is the correct and expected outcome for a version that introduces no functional changes.
If we had added tests for this version, what would they test? The only version-specific change is the window title string, and window title verification requires a running window — it is not a unit-testable property. The assets are byte-identical to the previous version. There is genuinely nothing new to test.
Gap Analysis
| Feature | Status | Notes |
|---|---|---|
| CalmLiquidTile class | N/A | Organizational; maps to existing still liquid implementation. |
| LiquidTile class | N/A | Organizational; maps to existing flowing liquid implementation. |
| Distort noise class | N/A | Organizational; maps to existing CombinedNoise / domain warping. |
| Emboss noise class | N/A | Library code; not used in terrain generator. |
| Rotate noise class | N/A | Library code; not used in terrain generator. |
| Scale noise class | N/A | Organizational; maps to existing noise scaling. |
| Synth base class | N/A | Interface; maps to existing noise trait/function pattern. |
| Coord data class | N/A | Data holder; equivalent functionality exists. |
| User data class | N/A | Part of deferred server save system. |
| LevelLoaderListener | N/A | Part of deferred level loading system. |
| Window title | DONE | Updated to c0.0.13a. |
| Asset extraction | DONE | Extracted to assets/c0.0.13a/. |
| JAR preservation | DONE | Copied to jars/c0.0.13a/. |
| GUI system | DEFERRED | Same deferral as c0.0.13a_03. |
| Server save/load | DEFERRED | Same deferral as c0.0.13a_03. |
| Liquid flow simulation | DEFERRED | Same deferral as c0.0.13a_03. |
Every “N/A” entry is a class that exists in the deobfuscated source but maps to functionality already implemented or already deferred. No new features to implement. No new gaps to track.
On Trivial Versions
This is the first version in the project where the port required no Rust code changes. It will not be the last. Minecraft’s version history includes hundreds of releases, and not all of them introduce meaningful gameplay changes. Some are bug fixes. Some are build configuration changes. Some, like this one, are the same game rebuilt with different settings.
The temptation is to skip these versions. To say “c0.0.13a is identical to c0.0.13a_03, therefore it does not need its own port, its own analysis, its own blog post.” But the project specification is clear: one commit per version, one tag per version, complete coverage. And there are good reasons for this beyond completeness.
First, the trivial version still needs verification. “This version is identical to the previous one” is a claim that must be tested, not assumed. We verified it by extracting the assets (byte-identical), reading the decompiled source (functionally identical), and running the test suite (all pass). Without that verification, “identical” is a guess. Guesses accumulate. After ten unverified “identical” versions, you have no idea whether your port still matches the game.
Second, the trivial version provides documentation. This blog post exists so that future readers — or future versions of ourselves — can look up c0.0.13a and understand what it was, why it exists separately from c0.0.13a_03, and what relationship it has to the versions around it. Without this documentation, c0.0.13a is a gap in the timeline. With it, the timeline is continuous.
Third, the trivial version teaches something. This version taught us that our deobfuscation of c0.0.13a_03 was correct. It taught us about Notch’s build pipeline and the toggle between obfuscated and readable builds. It taught us that the noise synthesis framework had a class hierarchy we partially missed during structural analysis. These lessons have no Rust code associated with them, but they are real lessons that inform future work.
The port is trivial. The understanding is not.
What I Learned
The most important thing I learned from c0.0.13a is that our c0.0.13a_03 deobfuscation was correct. Every class we identified by structure was confirmed by the deobfuscated names. Every behavior we attributed to an obfuscated class was validated by the readable source. The detective work held up. The workflow works.
The second thing I learned is that noise synthesis in early Minecraft was more sophisticated than the obfuscated source revealed. The Distort / Emboss / Rotate / Scale / Synth hierarchy is a composable noise framework, not just three utility classes. Whether these classes were all actively used in this version’s terrain generator or were library code for future use, the architecture is intentional and well-structured. Notch was thinking about terrain generation as a composition of transformations, not as a monolithic algorithm. This design philosophy — small, composable primitives combined into complex outputs — is what made Minecraft’s terrain generation extensible across hundreds of future versions.
The third thing I learned is about the rhythm of this project. Not every version is a sprint. Some versions are a checkpoint — a moment to verify, validate, and document before moving on. c0.0.13a is a checkpoint. The game has not changed. The source has become legible. The port is confirmed correct. We are ready for whatever comes next.
We have 870 versions to go. The next one might be obfuscated again. The next one might add new blocks, new physics, new rendering modes. The next one might be another trivial rebuild. We do not know. We take them as they come, one version at a time, each one analyzed, each one ported, each one documented.
The game is the same game. The source is readable now. The port continues.