The Revert: Analyzing rd-161348
The version where Notch decided that yesterday’s experiment was wrong and today’s job was to undo it.
One day after shipping the smallest Minecraft version to date — twenty-six files, 2,494 lines, a deliberate contraction — Notch shipped a version that put everything back. Twenty-eight files. Two thousand five hundred and ninety-six lines. Bush tiles, deterministic particles, the small crosshair, the windowed launch. Everything that rd-160052 had removed or changed, rd-161348 restored.
rd-161348 was released on May 16, 2009, and it is Minecraft’s first true revert. Not a partial rollback, not a “keep some changes and discard others.” A comprehensive undoing. The experimental cleanup of rd-160052 — removing bush, tuning particles to be stochastic, doubling the crosshair, tripling the block preview, switching to fullscreen — was evaluated and rejected. The code went back to approximately where it was before the experiment began.
This is the third version in three days. The cadence tells a story: build aggressively (rd-20090515), experiment with simplification (rd-160052), reject the experiment (rd-161348). Try, evaluate, revert. The full cycle of empirical development, completed in seventy-two hours.
What Was Restored
The Bush Returns
Bush (tile ID 6) is back. The Bush.java file is restored. The tile registration in Tile.java is restored. The bush rendering — two intersecting quads forming an X shape, dispatched through Java’s virtual method system from Tile.tiles[tileId].render() — works again.
The restored bush is byte-identical to the rd-20090515 bush. Same constructor, same tick behavior (die if dark, die if not on dirt or grass), same rendering geometry, same properties (non-solid, does not block light, no collision AABB). Nothing was learned from the experiment that led to changes in the bush implementation. It was removed wholesale and restored wholesale.
Why bring it back? The bush was Minecraft’s first non-solid tile, the first tile with non-standard rendering, and one of only two tiles with tick behavior. Its removal in rd-160052 simplified the tile system considerably — all remaining tiles were solid, all blocked light, all rendered as cubes, only grass had tick behavior. The system became uniform and easy to reason about.
But uniform and easy to reason about is not the goal. The goal is a game where the world feels alive and varied. Bush tiles, for all their architectural complexity, contributed to that goal. They were the first hint that the voxel world could contain more than solid cubes. Without them, the world was hills of grass and dirt and rock, with nothing breaking the cubic monotony.
We cannot know Notch’s exact reasoning. But the revert suggests that whatever problems bush caused (rendering complexity, tick interaction weirdness, the need for alpha testing), the absence of bush was worse. A world without vegetation looked wrong. The experiment proved the negative case: you can remove bush, and the code gets simpler, but the game gets emptier.
The Applet Returns (Sort Of)
MinecraftApplet.java is restored, but in a degraded form. In rd-20090515, it had init() and start() methods that created a Minecraft instance and started the game in an applet container. In rd-161348, it is an empty class:
public class MinecraftApplet extends Applet {
}
No methods. No functionality. It exists so that the class file exists — perhaps for build compatibility, perhaps as a placeholder for future work, perhaps because Notch had a build system that expected the file to be present. The applet wrapper is not functional in this version, but its skeleton is back in the codebase.
The Particles Revert
Every particle change from rd-160052 is undone.
The stochastic death system — a 10% random chance of dying each tick, producing a geometric distribution of lifetimes with no upper bound — is replaced by the deterministic age/lifetime system from rd-20090515. Each particle is born with a fixed lifetime (randomly chosen between 4 and 40 ticks), tracks its age, and dies when age reaches lifetime.
The size field, which was absent in rd-160052, returns. Each particle gets a random size between 0.5 and 1.0, used as a scale factor in rendering. The rd-160052 particles rendered at a fixed size; the rd-161348 particles vary, creating a more natural-looking debris cloud where some fragments are larger than others.
Gravity reverts from 0.06 to 0.04 per tick. The 50% increase in rd-160052 made particles fall faster and more aggressively, producing a compact downward spray. The revert to 0.04 restores the slightly floatier, more lingering debris pattern.
The speed formula reverts to * 0.4 horizontal with a + 0.1 upward bias, from rd-160052’s * 0.7 horizontal with no attenuation and no bias. The old formula produced a wider, more horizontal spray. The restored formula produces a tighter spray with a slight fountain effect — particles tend to arc upward briefly before falling.
The combined effect: rd-160052 particles were punchy and immediate. They sprayed wide, fell hard, and died randomly. rd-161348 particles are softer and more predictable. They arc gently upward, drift in a tight cone, and have fixed expiration dates. The aesthetic is less “decisive impact” and more “gentle scattering.”
Was the rd-160052 particle feel better or worse? This is a judgment call, and Notch made it: the old particles were better, or at least, the new particles were not better enough to keep. The deterministic lifetime system has one significant advantage the stochastic system lacks: a guaranteed upper bound. With age/lifetime, the longest any particle can live is 40 ticks (2 seconds). With 10% random death, a particle could theoretically survive indefinitely (though the probability drops exponentially). In a game where particles are generated in bursts of 64, unbounded lifetime means potential particle accumulation. The deterministic system caps the cost.
The HUD Shrinks Back
The crosshair reverts from +-8/9 pixels to +-4/5 pixels. The block preview scale reverts from 48 to 16.
In rd-160052, these changes were justified by the fullscreen default: at 1920×1080, small HUD elements are hard to see. But rd-161348 reverts FULLSCREEN_MODE to false. The game launches windowed again, in a 1024×768 window. At that resolution, the original +-4/5 crosshair is adequate and the 16-scale block preview is identifiable.
The fullscreen, HUD, and crosshair changes were a coherent set: fullscreen mode required larger HUD elements. Reverting fullscreen means the larger elements are no longer needed. The revert is consistent.
Alpha Testing Returns
glAlphaFunc(GL_GREATER, 0.5) is re-enabled in the OpenGL initialization. This was removed in rd-160052 because bush was the only tile requiring alpha testing (its texture has transparent regions rendered as an X-shaped cross). With bush back, alpha testing is needed again.
This is a clean example of feature coupling: bush requires alpha testing. Remove bush, remove alpha testing. Restore bush, restore alpha testing. The rendering infrastructure tracks the feature set.
What Changed (Not Just Reverted)
Package: A New Hybrid State
The package is com.mojang.minecraft, matching rd-20090515. But the entry point class is RubyDung.java, matching rd-160052. This is a state neither previous version had:
| Version | Package | Class |
|---|---|---|
| rd-20090515 | com.mojang.minecraft |
Minecraft.java |
| rd-160052 | com.mojang.rubydung |
RubyDung.java |
| rd-161348 | com.mojang.minecraft |
RubyDung.java |
The package says “this is Minecraft.” The class name says “this is RubyDung.” The project has an identity crisis, or more charitably, Notch reverted the package without bothering to rename the class. When you are iterating at the speed of one version per day, cosmetic consistency is not a priority.
Key Binding Shift
In rd-20090515, keys 1 through 5 mapped to rock, dirt, stone brick, wood, bush. In rd-160052, bush was removed and key 5 was remapped to wood (which was already on key 4).
rd-161348 does not restore the old mapping. Instead, bush gets key 7 (LWJGL key code 7, corresponding to keyboard key 6). Keys 1 through 5 retain their rd-160052 assignments. Bush is back, but on a new key.
This is a small detail that tells us something about the revert process. Notch did not simply check out the rd-20090515 source and recompile. He selectively restored features into the rd-160052 codebase. Bush came back, but the key mapping was updated rather than reverted. This suggests a conscious decision: bush deserves a key, but it does not need to displace wood from key 4 or claim the old key 5 slot.
Chunk Rendering: Dispatch vs. Special Case
In rd-20090515, Chunk.java contained explicit bush detection and X-shaped rendering code. In rd-160052, that code was removed along with bush. In rd-161348, the chunk mesher does not re-add the bush special case. Instead, the tile rendering dispatch handles it:
Tile.tiles[tileId].render(t, level, layer, x, y, z);
When tileId is 6, this dispatches to Bush.render(), which produces the X-shaped cross geometry. The chunk mesher does not know or care that bush exists. It calls render() on whatever tile type is registered at the ID, and the tile type handles its own geometry.
This is actually cleaner than rd-20090515, where the chunk mesher had an explicit if tile is bush, do special rendering check. The polymorphic dispatch via the tile registry makes the mesher tile-type-agnostic. Bush can render however it wants without the mesher knowing about it.
Whether this is the same as rd-20090515’s actual Chunk.java bytecode or a decompiler artifact is unclear. The behavioral result is the same: bush renders as an X-shaped cross.
What Did NOT Change
Twenty-two of the twenty-eight files are functionally identical to rd-160052 (modulo the package declaration change from com.mojang.rubydung to com.mojang.minecraft):
- Level.java — terrain generation, random ticks, tile-aware queries, save/load: unchanged.
- Entity.java, Player.java, Zombie.java, ZombieModel.java — the entire entity system: unchanged.
- Timer.java — still 20 TPS.
- AABB.java — collision: unchanged.
- LevelRenderer.java, DirtyChunkSorter.java, Frustum.java, Tesselator.java — rendering infrastructure: unchanged.
- PerlinNoiseFilter.java — terrain generation: unchanged.
- GrassTile.java, DirtTile.java — grass and dirt: unchanged.
- Vec3.java, Vertex.java, Polygon.java, Cube.java — character models: unchanged.
- HitResult.java, Textures.java, LevelListener.java — utilities: unchanged.
- ParticleEngine.java — particle lifecycle manager: unchanged.
Player physics are the 20 TPS constants (0.1 ground speed, 0.02 air speed, 0.08 gravity, 0.5 jump velocity, 0.7 ground friction). These were set in rd-20090515 when the timer moved to 20 TPS and have not changed since. The player feels the same as it did two versions ago.
The Revert Pattern
rd-161348 is interesting not for any individual change but for what it reveals about how Notch worked.
The three-day sequence (May 14-16, 2009) is a complete experiment cycle:
- Build (rd-20090515): Add nine new files. Terrain, tiles, particles, ticks. The largest expansion.
- Simplify (rd-160052): Remove two files. Delete bush, delete applet, tune particles, enlarge HUD, go fullscreen. The first contraction.
- Revert (rd-161348): Restore two files. Bring bush back, revert particles, shrink HUD, go windowed. The contraction is rejected.
This is the scientific method applied to game development:
– Hypothesis: “The game is better without bush, with stochastic particles, with bigger HUD elements, in fullscreen.”
– Experiment: Ship rd-160052 with those changes.
– Observation: Play the game. Evaluate.
– Conclusion: The hypothesis was wrong (or at least, not right enough to keep).
– Action: Revert.
The revert is the hardest step. Most developers, having made changes and shipped them, are reluctant to undo. Sunk cost fallacy: “I already wrote the new particle system, I should keep it.” Status quo bias in reverse: “The current version has these changes, changing back is work.” Pride: “I made these decisions, reversing them admits I was wrong.”
Notch reversed them in one day. The experiment ran for approximately 24 hours — one development cycle of play, evaluate, decide. The stochastic particles were interesting but not better. The big crosshair was visible but not necessary in a window. The bush removal simplified the code but emptied the world. The experiment was informative and its result was: no.
This is what rapid prototyping looks like when it works. Not every change is kept. Not every simplification improves the game. Not every refactor is permanent. The version control system preserves the experiment for posterity, and the next version moves forward with what actually worked.
The bush was worth more than the simplicity its absence bought. Notch had the data and he made the call. The bushes returned.
By the Numbers
| Metric | rd-160052 | rd-161348 | Delta |
|---|---|---|---|
| Files | 26 | 28 | +2 |
| Lines | 2,494 | 2,596 | +102 |
| Tile types | 5 (+ air) | 6 (+ air) | +1 |
| Non-solid tiles | 0 | 1 (bush) | +1 |
| Tiles with tick behavior | 1 (grass) | 2 (grass, bush) | +1 |
| Particle fields | 5 (no age/lifetime/size) | 7+ (incl. age, lifetime, size) | +2 |
| Particle gravity | 0.06 | 0.04 | -33% |
| Crosshair pixels | +-8/9 | +-4/5 | ~0.5x |
| Block preview scale | 48 | 16 | 0.33x |
| Unchanged files | — | 22 of 28 | 79% |
Positive 102 lines. The game got a little longer and arguably got its soul back. The bushes rustle in the sunlight. The particles drift gently upward before settling. The crosshair is small and precise. The world is windowed and humble.
Sometimes progress means undoing what you did yesterday.