- Notifications
You must be signed in to change notification settings - Fork11
NBT & Anvil save format library
License
Minestom/Hephaistos
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
This library is both a NBT library and a Minecraft Anvil format library.
Made in Kotlin, it is accessible for all languages that run on the JVM.As it is in Kotlin, this means your project may have to add a new dependency on the Kotlin runtime library.
Minestom required an NBT library during its development. Available librairies were deemed either too heavy, or lacking in features.
Hephaistos has been created in hopes to provide a library for handling NBT data and MCA files with a clean API.
This project is supposed to be used as a library.
It is available on Maven Central with the following coordinate:io.github.jglrxavpok.hephaistos:common:<version>
The Gson compatibility layer is available at:io.github.jglrxavpok.hephaistos:gson:<version>
Hephaistos can read NBT from SNBT, binary format or (with additional dependencies) JSON.See more in the "parsing" section below for more information.
Based on the up-to-date specs present atWiki.vgand on theMinecraft Wiki.
While the tests insrc/test/java/nbt
can help comprehension, here are a few more examples to show the philosophy:
// false represents the uncompressed status of the filetry (NBTReaderreader =newNBTReader(newFile("servers.dat"),false)) {NBTCompoundtag = (NBTCompound)reader.read();NBTList<NBTCompound>servers =tag.getList("servers");for(NBTCompoundserver :servers) {Stringid =server.getString("ip");Stringname =server.getString("name");if(server.containsKey("acceptTextures")) {// ... }if(server.containsKey("icon")) {// ... }// Do something with the information }}catch (IOException |NBTExceptione) {e.printStackTrace();}
varlevel =NBT.Compound(root -> {root.put("Data",NBT.Compound(data -> {data.set("raining",NBT.Byte(0));data.set("SpawnX",NBT.Int(0));data.set("SpawnZ",NBT.Int(0)); }));});try(NBTWriterwriter =newNBTWriter(newFile("level.dat"),CompressedMode.GZIP)) {writer.writeNamed("",level);}catch (IOExceptione) {e.printStackTrace();}
Hephaistos can parse and write NBT data from/to SNBT, NBT binary format or JSON.
UseNBTWriter#writeNamed
andNBTReader#read()
.
If you want to read SNBT, useSNBTParser#parse
with aReader
which contains the SNBT string to parse.
If you want to write SNBT, simply use thetoSNBT()
method on anyNBT
instance.
Using JSON requires an additional library. For the moment, only Gson is supported by Hephaistos.
To access the Gson-based reader and writer, you will need to add a new dependency in yourbuild.gradle
file (example with Jitpack.io names):
dependencies { api("com.github.jglrxavpok:Hephaistos:${project.hephaistos_version}") implementation("com.github.jglrxavpok:Hephaistos:${project.hephaistos_version}:gson") implementation("com.github.jglrxavpok:Hephaistos:${project.hephaistos_version}") { capabilities { requireCapability("org.jglrxavpok.nbt:Hephaistos-gson") } }}
Built upon the NBT library part, themca
package allows loading and saving MCA (Minecraft Anvil) files.
Contrary toNBTReader
andNBTWriter
,RegionFile
requires aDataSource
instead of a InputStream/OutputStream.The reasoning is thatDataSource
allows both reads and writes to happen at the same time on the same file.RegionFile
has a constructor to directly use aRandomAccessFile
to read from disk.If you want to work in memory, you can useGrowableSource
One must be careful of OutOfMemory errors when reading lots of chunks from a RegionFile. UseRegionFile#forget
to unload a chunk column from the internal chunk cache to relieve memory.
Finally, Hephaistos allows you to load and save Entities/TileEntities/Lighting but provide very little in the way of support for these features, you will have to make sure your entities are correct by yourself.In the event that you find that a convenience method would help you in your work, do not hesitate to submit a Pull Request or post an issue on this Github repository.
Here comes the part you are all waiting for, examples!
It is possible to set blocks directly fromRegionFile
:
// create the region from a given DataSource. 0,0 is the region coordinates (a region is 32x32 chunks)RegionFileregion =newRegionFile(dataSource,0,0);BlockStatestone =newBlockState("minecraft:stone");for (intx =0;x <16;x++) {for (intz =0;z <16;z++) {for (inty =0;y <256;y++) {// Sets the block inside the 0,0 and 1,0 chunksregion.setBlockState(x,y,z,BlockState.Air);region.setBlockState(x +16,y,z,stone); } }}// save chunks that are in memory (automatically generated via setBlockState) to disk// without this line, your chunks will NOT be saved to diskregion.flushCachedChunks();
It is also possible to create chunks on-demand:
RegionFileregion =newRegionFile(dataSource,0,0);ChunkColumnchunk0 =region.getOrCreateChunk(0,0);ChunkColumnchunk1 =region.getOrCreateChunk(1,0);// just 3 for-loops over the entire chunk to set the blocks via ChunkColumn#setBlockStatefillChunk(chunk0,BlockState.Air);fillChunk(chunk1,newBlockState("minecraft:stone"));// write the chunks to disk. It is also possible to use flushCachedChunks() like in// the previous example, but you can select which chunks to saveregion.writeColumn(chunk0);region.writeColumn(chunk1);
// Load your regionRegionFileregion =newRegionFile(dataSource,0,0);// Get your chunk. May return null if the chunk is not present in the file// (ie not generated yet)ChunkColumncolumn0_0 =region.getChunk(0,0);if(column0_0 ==null) {// throw or whatever}// print all blocks at x,0,z in the ChunkColumn// in an usual Minecraft world, all "minecraft:bedrock" in the Nether or overworld// XYZ are chunk local (ie in a 16x256x16 cube)// The method WILL throw IllegalArgumentException if XYZ are not validfor (intz =0;z <16;z++) {for (intx =0;x <16;x++) {System.out.println(column0_0.getBlockState(x,0,z).getName());// a Map<String, String> is available in BlockState#getProperties// to analyse the properties of the block state (like 'lit' or 'facing' for a furnace) }}// both following methods return a NBTList<NBTCompound> with the data from entities/tileEntities// it is allowed to modify these lists directly to alter the data for later-saving// other methods in the like exist for other features (ticks, heightmaps, etc.)column0_0.getTileEntities()column0_0.getEntities()
Feel free to dive in!Open an issue or submit PRs.
Thanks to the following people who greatly helped the development of this project:
- @LeoDog896. Worked on the v2 rework of the library.
MIT © Xavier "jglrxavpok" Niochaut
About
NBT & Anvil save format library