Static teardownMinecraft — Pocket Editionv0.2.0 alpha

Ninecraft, disassembled

A 2.8 MB APK stamped 11 February 2012. Inside: a Java-to-C++ port of Minecraft Beta carrying its original class names, an SVN path from a Windows workstation, and 2.25 MB of uncompressed sound effects welded into the executable.

Package
com.mojang.minecraftpe
Version
0.2.0 · code 2005
Built
2012‑02‑11 03:46
Min SDK
9 · Android 2.3
ABI
armeabi‑v7a only
SHA‑1
f60474ae…2d3c4b26

Shape of the thing70 files

A native game in a Java costume

Only 44 KB of the APK is Dalvik bytecode, and almost none of it is Minecraft. The classes.dex holds 44 classes: 25 are Google's License Verification Library, a handful are a preferences screen and an ASCII-only text field, and exactly one matters — MainActivity, a subclass of NativeActivity that exists to hand 47 methods down to C++ over JNI.

Everything else lives in libminecraftpe.so. The build is against OpenGL ES 1.x fixed-function — libGLESv1_CM.so, no shaders anywhere — with libOpenSLES.so for audio and the NDK's android_native_app_glue event loop for input.

What C++ asks Java for

getScreenWidthgetScreenHeightgetPixelsPerMillimeterisTouchscreen setIsPowerVRvibratetickquit initiateUserInputgetUserInputStatusgetUserInputStringdisplayDialog getOptionStringsgetDateStringgetImageData saveScreenshotpostScreenshotToFacebook checkLicensehasBuyButtonWhenInvalidLicensebuyGame

That list is the whole platform layer. setIsPowerVR is a per-GPU workaround flag; the Java side logs "Is PowerVR? : " and "Experimental on this device!" next to it. And postScreenshotToFacebook is the other half of the in-game camera item — screenshots land at /games/com.mojang/img_0000.jpg.

The composition problem4.49 MB unpacked

Half the game is sound effects

The APK ships zero audio files. Every asset is a PNG. The sounds are 43 raw PCM arrays compiled directly into the .data section of the shared library as C constants — PCM_zombie3, PCM_grass1, PCM_door_open — and they account for 99.9% of that section.

Embedded PCM audio52.4%
Native code .text19.6%
Textures (31 PNGs)6.7%
Symbols, res, dex, sig21.3%

28 seconds of audio, stored at CD quality, is the single largest thing in Minecraft Pocket Edition. Each array carries a 16-byte header that makes the format self-describing:

// PCM_grass1, .data @ 0x19ffd4
01 00 00 00   channels      = 1        (mono)
02 00 00 00   bytesPerSample= 2        (16-bit signed)
44 ac 00 00   sampleRate    = 44100
22 56 00 00   numSamples    = 22050    (0.500 s)
... 44100 bytes of interleaved PCM ...

All 43 headers validate against their symbol sizes exactly, so the set extracts losslessly to WAV. The encoding is also not quite consistent: splash is the lone 11025 Hz clip, and click is the lone stereo one.

GroupClipsBytesNote
zombie6678,136idle ×3, hurt ×2, death
sheep3253,624only other mob voice
footsteps20693,352cloth, grass, gravel, sand, stone, wood
glass3183,018break
world7299,478explode, splash, pop, click, doors
hurt186,392player damage
Referenced but not shipped

The code names mob.chicken, mob.cow, mob.pig and their hurt/death variants, but no PCM_ array exists for any of them. Chickens, cows and pigs are silent in this build. The texture misc/vignette.png is likewise requested by the renderer and absent from the APK.

Symbols7,915 dynamic entries

Stripped, but exported wide open

file reports the library as stripped, which is true only of the debug tables. The dynamic symbol table survives at full width — a 273 KB .dynstr — so every C++ class, method signature and static member is legible by name. 425 vtables recover the type hierarchy outright.

The names are the giveaway: Tile, Level, Mob, Tesselator, ItemInstance, LevelChunk, HitResult, Mth. These are not fresh C++ inventions — they are the MCP deobfuscation names from Minecraft Beta's Java source, carried over one-for-one. Pocket Edition was a hand port of the desktop codebase, and it kept the desktop vocabulary.

The application class is named NinecraftApp.

ClassMethodsRole
Tile157block behaviour base
Level132world state + ticking
Item84item base
Entity81entity base
Mob68living entity
Player53
Minecraft50game root
Inventory48
LevelRenderer34
Tesselator31immediate-mode geometry

Content inventory58 blocks · 47 items

What was actually in the game

Static members on Tile and Item enumerate the registry directly. Note emerald throughout — in Beta-era naming that is diamond, and the parallel string table confirms it, listing oreDiamond and pickaxeDiamond against the same slots.

Blocks

rockgrassdirtstoneBrickwoodtreeTrunkleavessandgravelglass coalOreironOregoldOreemeraldOrelapisOreredStoneOreredStoneOre_lit ironBlockgoldBlockemeraldBlocklapisBlock watercalmWaterlavacalmLavaicesnowtopSnow clothsandStonemossStoneobsidianbookshelfredBrick stairs_woodstairs_stonestoneSlabstoneSlabHalffencefenceGateladder door_wooddoor_irontorchtntfire flowerrosemushroom1mushroom2cactusreedsclayfarmland invisible_bedrockinfo_updateGame1info_updateGame2info_reserved6

Items

sword_woodsword_stonesword_ironsword_goldsword_emerald pickAxe_×5shovel_×5hatchet_×5 ironIngotgoldIngotemeraldbrickclayyellowDustsulphur stickbowlstringfeatherleatherboneslimeBallpaperbook wheatsugarreedsarrowsnowBallshearscompassclock door_wooddoor_ironcamera

Mobs

Eight mob textures ship. Five of those mobs have an entity class behind them.

MobTextureModelRendererEntity classSound
Pigyesyesyesyes
Cowyesyesyesyes
Chickenyesyesyesyes
Sheepyesyesyesyesyes
Zombieyesyessharedyesyes
Creeperyesyesyesno
Spideryesyesyesno
Skeletonyesyessharedno
TripodCameraitem/yesyes

Creeper, spider and skeleton are half-built: art and rendering code present, no entity, no AI, no spawn path. CreeperRenderer::getOverlayColor — the flash-white-before-detonating routine — exists for a creeper that cannot be created. Zombie is the only hostile mob with a real implementation.

TripodCamera is the pair to the camera item: place it, it photographs you, and the shot goes out through postScreenshotToFacebook.

Biomes

RainforestSwamplandSeasonal ForestForestSavannaShrublandTaigaPlainsDesertIce DesertTundraFlatBiome

The full Beta biome table, driven by PerlinNoise and ImprovedNoise, with worldgen features for trees (oak, birch, pine, spruce), ore, clay, flowers, reeds, cactus, springs and LargeCaveFeature.

Negative spacethe interesting part

What isn't there

Absences in a symbol table are strong evidence, because a stripped-but-exported binary hides nothing. Searching the full 7,915 symbols for crafting turns up exactly one hit: Item::hasCraftingRemainingItem(), a vestigial method inherited from the Java port with no system attached to it.

workbenchfurnacechestbedRecipeCraftingContainerredstone wirerailsignbucketbowsaplings

No crafting, no smelting, no storage. There is ore in the ground and a diamond pickaxe class in the registry, with no path in the game connecting them — CreativeMode hands you blocks and SurvivalMode lets you break them, and that is the whole loop. There are also no sounds for it: the Synth class is present but the ambient and music systems are not.

Also missing

Only one ABI is shipped — armeabi-v7a. No ARMv5, no x86. A 2012 device without a v7a chip could install this APK and never launch it.

Multiplayer30 packet types

RakNet over WiFi, and nothing else

Networking is RakNet, vendored into the tree rather than linked. The transport is LAN broadcast to 255.255.255.255, advertising with the string MCCPP;Demo; — the UI calls it "Scanning for WiFi Games…". There is no account system, no server list, no internet play; the only remote hostname compiled in is localhost.

The protocol is a flat set of 30 packets split between ClientSideNetworkHandler and ServerSideNetworkHandler, with one player acting as host:

LoginLoginStatusReadyStartGameRespawnSetTimeSetHealthMessage AddPlayerRemovePlayerAddMobAddItemEntityTakeItemEntityRemoveEntity MovePlayerMoveEntitySetEntityDataEntityEventAnimateInteract RequestChunkChunkDataPlaceBlockRemoveBlockUpdateBlockLevelEvent ExplodeUseItemPlayerEquipment

Version negotiation is a single integer compare, producing the two failure strings "Could not connect: Outdated client!" and "Could not connect: Outdated server!". The client is not trusted blindly — "Attempted to modify local player's inventory" is a guard in the client-side handler.

Save formatNBT, inherited

Desktop's file format on a phone

The full NBT tag hierarchy is ported intact — EndTag through CompoundTag, with the human-readable TAG_Byte_Array / TAG_Compound debug names still compiled in. Worlds live on external storage:

/sdcard/games/com.mojang/minecraftWorlds/<world>/
    level.dat      RandomSeed, GameType, LevelName, LastPlayed,
                   SizeOnDisk, StorageVersion, Platform, Player
    chunks.dat     RegionFile — single-file McRegion variant
    player.dat
    entities.dat

ExternalFileLevelStorageSource::requiresConversion and the StorageVersion / generatorVersion fields are already present, so the format was versioned for migration from the start — three weeks into the product's life.

Provenancebuild tree leak

Fingerprints left in the binary

RakNet's assertion macros bake __FILE__ into the release build, which preserves the absolute path of the machine that compiled it:

C:\dev\subversion\mojang\minecraftcpp\trunk\handheld\project
      \lib_projects/raknet/jni/RakNetSources/ReliabilityLayer.cpp

Four things fall out of one string. The project was called minecraftcpp, not Pocket Edition. It was under Subversion, on trunk. It was built on Windows, from C:\dev. And handheld as a path component alongside lib_projects suggests the multi-platform structure that would later carry this engine to consoles.

Signature

Signed with Mojang AB's own certificate, self-issued in Stockholm on 7 August 2011 — nine days before Pocket Edition's first release — with a 2038 expiry. 2048-bit RSA, SHA-1. Genuine retail build.

The Xperia Play, still in the manifest

0.1.0 shipped exclusively for Sony Ericsson's Xperia Play. This build still declares that heritage, but defanged:

<meta-data android:name="xperiaplayoptimized_content" …/>
<uses-library android:name="xperiaplaycertified"
              android:required="false"/>

required="false" is the one attribute that makes the difference. The Xperia gamepad integration is still declared, so the device that launched the game keeps its optimised path — but the library is now optional, so Google Play will serve the APK to any ARMv7 handset running Gingerbread. That single boolean is the mechanism behind "0.2.0 runs on everything".

The paid and demo builds also share one binary: Minecraft_Market and Minecraft_Market_Demo both ship in this DEX, and the native side carries the demo's screens — DemoChooseLevelScreen, BuyButton, "Not available in the demo version". Only the manifest's launcher entry decides which one you get.

Methodno apktool required

How this was pulled apart

The extracted sounds are on disk at …/scratchpad/pe/sounds/ — 43 WAVs, 2.25 MB.