Polar World Format

repository·main·Indexed 41 days ago

https://github.com/hollow-cube/polar

A world format for Minestom designed for small worlds and user-generated content, prioritizing small file sizes and fast loading. It provides a PolarLoader for Minestom Instances, tools to convert Anvil worlds via AnvilPolar, and support for custom user data through the PolarWorldAccess interface.

Tokens
3.6K
Snippets
10
Records
10
Agent score
2%

What's inside Polar

  1. Store custom user data with PolarWorldAccess

    main

    By default, Polar only stores blocks, biomes, block entities, and light data. To store arbitrary user-specific data, implement the PolarWorldAccess interface and attach it to your PolarLoader using .setWorldAccess(PolarWorldAccess).

    In loadChunkData, you read data from the NetworkBuffer. In saveChunkData, you write data to the NetworkBuffer.

    public class UpdateTimeWorldAccess implements PolarWorldAccess {
        private static final Logger logger = LoggerFactory.getLogger(UpdateTimeWorldAccess.class);
    
        @Override
        public void loadChunkData(@NotNull Chunk chunk, @Nullable NetworkBuffer userData) {
            if (userData == null) return; // No saved data, probably first load
    
            long lastSaveTime = userData.read(NetworkBuffer.LONG);
            logger.info("loading chunk {}, {} which was saved at {}.", chunk.getChunkX(), chunk.getChunkZ(), lastSaveTime);
        }
    
        @Override
        public void saveChunkData(@NotNull Chunk chunk, @NotNull NetworkBuffer userData) {
            userData.write(NetworkBuffer.LONG, System.currentTimeMillis());
        }
    }
    
    // Usage:
    new PolarLoader(world).setWorldAccess(new UpdateTimeWorldAccess());
  2. Use Polar as a ChunkLoader for Minestom

    main

    Polar provides a PolarLoader implementation for Minestom Instances. This allows you to load a world from a .polar file and save changes back to storage using the standard Minestom API.

    // Loading
    Instance instance=...;
    instance.setChunkLoader(new PolarLoader(Path.of("/path/to/file.polar")));
    
    // Saving
    instance.saveChunksToStorage();
  3. Install Polar via Maven

    main

    Polar is available on Maven Central. Add the following to your build.gradle file to include the dependency. Replace <see releases> with the latest version (e.g., 1.16.0).

    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation 'dev.hollowcube:polar:<see releases>'
    }
  4. Convert Anvil worlds to Polar

    main

    You can use AnvilPolar to convert existing Anvil world directories into the Polar format. Note that conversion is only guaranteed to work on the latest version worlds.

    var polarWorld = AnvilPolar.anvilToPolar(Path.of("/path/to/anvil/world/dir"));
    var polarWorldBytes=PolarWriter.write(polarWorld);
  5. Filter chunks using ChunkSelector

    main

    Most Polar functions accept an optional ChunkSelector to limit operations to a specific area. For example, you can use ChunkSelector.radius(int) to select chunks within a certain radius of a coordinate.

    // Convert an anvil world while only selecting a 5 chunk radius around 0,0
    AnvilPolar.anvilToPolar(Path.of("/path/to/anvil/world/dir"), ChunkSelector.radius(5));
  6. Reference the Polar Block Entity data structure

    main

    Block Entities are stored within chunks and can optionally include an ID and NBT data.

    ### Block Entity
    
    | Name                | Type    | Notes |
    |---------------------|---------|----------------------|
    | Chunk Pos           | int     |                      |
    | Has ID              | bool    | If unset, Block Entity ID is omitted |
    | Block Entity ID     | string  |                      |
    | Has NBT Data        | bool    | If unset, NBT Data is omitted        |
    | NBT Data            | nbt     |                      |
  7. Reference the Polar World data structure

    main

    The World segment follows the Header and defines the vertical bounds of the world and the collection of chunks.

    ### World
    
    | Name             | Type         | Notes                                         |
    |------------------|--------------|-----------------------------------------------|
    | Min Section      | byte         | For example, -4 in a vanilla world            |
    | Max Section      | byte         | For example, 19 in a vanilla world           |
    | User data        | array[byte]  | Arbitrary user data segment                   |
    | Number of Chunks | varint       | Number of entries in the following array      |
    | Chunks           | array[chunk] | Chunk data                                    |
  8. Reference the Polar Chunk data structure

    main

    Chunks contain spatial information (X, Z), vertical sections, block entities, heightmaps, and user data.

    ### Chunk
    
    | Name                     | Type                | Notes                                                 |
    |--------------------------|---------------------|-------------------------------------------------------|
    | Chunk X                  | varint              |                                                       |
    | Chunk Z                  | varint              |                                                       |
    | Sections                 | array[section]      | `maxSection-minSection+1` entries                      |
    | Number of Block Entities | varint              | Number of entries in the following array               |
    | Block Entities           | array[block entity] |                                                       |
    | Heightmap Mask           | int                 | A mask indicating which heightmaps are present. See `AnvilChunk` for flag constants. |
    | Heightmaps               | array[bytes]        | One heightmap for each bit present in Heightmap Mask  |
    | Length of user data      | varint              | Number of entries in the following array              |
    | User data                | array[byte]         | Arbitrary user data segment                           |
  9. Reference the Polar Section data structure

    main

    Sections contain the actual block and biome data, including palettes and lighting information.

    ### Sections
    
    | Name                      | Type                | Notes                                                                 |
    |---------------------------|---------------------|-----------------------------------------------------------------------|
    | Is Empty                  | bool                | If set, nothing follows                                                              |
    | Block Palette Size         | varint              |                                                                       |
    | Block Palette             | array[string]       | Entries are in the form `minecraft:block[key1=value1,key2=value2]`     |
    | Block Palette Data Length  | varint              | Only present if `Block Palette Size > 1`                            |
    | Block Palette Data        | array[long]         | See the anvil format for more information about this type            |
    | Biome Palette Size         | varint              |                                                                       |
    | Biome Palette             | array[string]       |                                                                       |
    | Biome Palette Data Length | varint              | Only present if `Biome Palette Size > 1`                             |
    | Biome Palette Data        | array[long]         |                                                                       |
    | Block Light Data Content  | byte                | 0 = no lighting, 1 = all zero, 2 = all max, 3 = present after          |
    | Block Light               | bytes               | A 2048 byte long nibble array, only present if above = 3           |
    | Sky Light Data Content    | byte                | 0 = no lighting, 1 = all zero, 2 = all max, 3 = present after        |
    | Sky Light                 | bytes               | A 2048 byte long nibble array, only present if above = 3             |
  10. Reference the Polar v1.0 file format structure

    main

    The Polar format is a binary format (unlike the NBT-based Anvil format) used for world data. The file structure is hierarchical, starting with a Header, followed by World data, which contains Chunks, which in turn contain Sections and Block Entities.

    ### Header
    
    | Name           | Type   | Notes                                                                   |
    |----------------|--------|-------------------------------------------------------------------------|
    | Magic Number   | int    | `Polr`                                                                  |
    | Version        | short  |                                                                         |
    | Compression    | byte   | 0 = None, 1 = Zstd                                                      |
    | Length of data | varint | Uncompressed length of data (or just length of data if `Compression=0`) |
    | World          | world  |                                                                         |