NBTExplorer icon indicating copy to clipboard operation
NBTExplorer copied to clipboard

Pocket Edition World Save Compatibility

Open jocopa3 opened this issue 8 years ago • 0 comments

Basic Info

Adding support for pocket edition world saves isn't as daunting as it seems. First, the level.dat file is simply compressed using the zlib format, but is otherwise a normal NBT file. On top of that, the LevelDB format PE/Win10 uses is fairly straightforward to work with.

Adding LevelDB Support

On Mac/Linux, compile Mojang's LevelDB-MCPE as a .so or .dylib and link it to NBTExplorer at runtime.

On Windows, I have a working Visual Studio 2015 project which is setup to compile Mojang's LevelDB-MCPE which as a DLL (both x86 and x64).

The generated libraries have both C++ and C functions declared. In C#, it'd probably be easier to use the C functions as the basis for DLL/Native imports.

Setting up LevelDB

Create a new instance of Options by calling Pointer leveldb_options_create(); this will return a pointer to an instance of Options. Make sure to specify the compression type as Zlib:

// Specify 2 as the compression type, which is a constant that stands for ZLib compression
void leveldb_options_set_compression(Pointer options, int compressionType) 

Afterwards, create a new instance of LevelDB by calling:

// leveldb_open returns a pointer to the LevelDB instance.
// Error pointer is a reference which stores any errors that occur while opening the database
Pointer leveldb_open(Pointer options, String dbFolderPath, Pointer errorPointer)

Before you can read from the database, you need to create an instance of ReadOptions by calling Pointer leveldb_readoptions_create(); doing so will return a pointer to an instance of ReadOptions. There is no need to change the default read options.

After that, you can call leveldb_get like so:

// returns a pointer to a byte array, the length of which is stored in a pointer to valLength
Pointer leveldb_get(Pointer db, Pointer readOptions, 
    byte[] keyAsBytes, int keyLength, 
    Pointer valLength, Pointer errorPointer)

Writing to the database is the same process as reading. Create an instance of WriteOptions by calling Pointer leveldb_writeoptions_create(); once again, it returns a pointer to an instance of WriteOptions, and the default options will again suffice.

Next call leveldb_put like so:

void leveldb_get(Pointer db, Pointer writeOptions, 
    byte[] keyAsBytes, int keyLength, 
    byte[] dataToWrite, int dataLength, 
    Pointer errorPointer)

Finally, to close the database, call: void leveldb_close(Pointer db)

PE/Win10 Key Values

Here are some basic keys stored as UTF-8 strings which return NBT byte arrays:

  • "BiomeData"
  • "Overworld"
  • "Nether"
  • "TheEnd"
  • "mVillages"
  • "portals"
  • "~local_player"
  • "AutonomousEntities"
  • "dimension0"
  • "dimension1"
  • "dimension2"

Chunk NBT data is a little bit trickier as the keys aren't "readable". The format is described on the Minecraft Wiki: https://minecraft.gamepedia.com/Pocket_Edition_level_format

Read both the 0.9.0 and 1.0.0 sections; the only difference between the 0.9.0 and 1.0.0 LevelDB format is how keys for chunks are stored (i.e. in 1.0.0 chunks are split up into 16x16x16 subchunks). The key structure for both versions is still the same, and the way the game stores chunk NBT data (both for block entities and regular entities) hasn't changed.

jocopa3 avatar Jan 23 '17 22:01 jocopa3