Render Minecraft Maps
This project is primarily a learning tool for me to learn Rust. I mostly work with other languages, such as PHP, Python, and JavaScript, all of which were self-taught. I learn through immersion, and this project is an example of this. The following are my goals and how I intend to meet them:
You can't have a working codebase if the syntax is wrong!
Minecraft NBT data provides ample opportunity to learn how to convert data between different types, parse data from raw bytes, and much more.
This will be part of the process of reading data from the Minecraft files in raw format to parse as NBT data, as well as manipulating and saving image data back onto the filesystem.
This is a list of things I have done/need to do which is updated as I think of things
- Decide on config structure
- Create full valid config file
- Implement default values for missing settings
- Validate defined render dimension
- Add checks and exits for invalid inputs
- Verify/create given output directory
- Go through header table to identify chunks
- Decompress raw bytes to NBT bytes
- Implement NBT parser for region chunks
- Extract data version of chunk
- Collect x, y, z coordinates
- Compile block states pallet list
- Calculate block and sky lighting values
- Identify each type of NBT format tag
- Create ability to ingest each data type
- Create an NBT struct of tags (is this necessary?)
- Check for valid default/given texture path
- Add directory traversal methods for
.jar/.ziparchives - Create cache directory named by hash of texture container file
[ ] Add drill-down methods for extracting block textures on-demand- Extract all textures into cache directory
- Create staging area for texture files (aka cache)
I need to figure out how to extract the blockstate and model data from the minecraft jar so as to dynamically apply the block textures to the render and not have to manually hard-code these values. This is the best long-term solution for project maintenance, but means extra work up-front.
- Add
jar\assets\minecraft\blockstates\*content to cache - Add
jar\assets\minecraft\models\block\*content to cache Figure out how blockstates correlate to nbt data- Determine how to map textures from model data
{ "variants": {
"snowy=false": [
{
"model": "minecraft:block/grass_block"
},
{
"model": "minecraft:block/grass_block",
"y": 90
},
{
"model": "minecraft:block/grass_block",
"y": 180
},
{
"model": "minecraft:block/grass_block",
"y": 270
}
],
"snowy=true": {
"model": "minecraft:block/grass_block_snow"
}
}
}{ "parent": "block/block",
"textures": {
"particle": "block/dirt",
"bottom": "block/dirt",
"top": "block/grass_block_top",
"side": "block/grass_block_side",
"overlay": "block/grass_block_side_overlay"
},
"elements": [
{ "from": [ 0, 0, 0 ],
"to": [ 16, 16, 16 ],
"faces": {
"down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" },
"up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "up", "tintindex": 0 },
"north": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "north" },
"south": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "south" },
"west": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "west" },
"east": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "east" }
}
},
{ "from": [ 0, 0, 0 ],
"to": [ 16, 16, 16 ],
"faces": {
"north": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "tintindex": 0, "cullface": "north" },
"south": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "tintindex": 0, "cullface": "south" },
"west": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "tintindex": 0, "cullface": "west" },
"east": { "uv": [ 0, 0, 16, 16 ], "texture": "#overlay", "tintindex": 0, "cullface": "east" }
}
}
]
}
Further thoughts: the block model json files appear to take the block name and link the faces to associated textures. The problem now appears to be that there isn't a completely consistent block:texture mapping structure, as some model data will link to other model data, which then substitutes some texture location mappings with other strings, example:
{
"parent": "minecraft:block/cube_column",
"textures": {
"end": "minecraft:block/deepslate_top",
"side": "minecraft:block/deepslate"
}
}{
"parent": "block/cube",
"textures": {
"particle": "#side",
"down": "#end",
"up": "#end",
"north": "#side",
"east": "#side",
"south": "#side",
"west": "#side"
}
}{
"parent": "block/block",
"elements": [
{ "from": [ 0, 0, 0 ],
"to": [ 16, 16, 16 ],
"faces": {
"down": { "texture": "#down", "cullface": "down" },
"up": { "texture": "#up", "cullface": "up" },
"north": { "texture": "#north", "cullface": "north" },
"south": { "texture": "#south", "cullface": "south" },
"west": { "texture": "#west", "cullface": "west" },
"east": { "texture": "#east", "cullface": "east" }
}
}
]
}- Render overworld chunk y-slice top-down
- Render full overworld chunk top-down without fluid
- Render full overworld chunk top-down with fluid
- Render nether top-down sans roof
- Render any isometric chunk section
- Render any isometric full chunk
- Figure out how to handle non-solid blocks (fence, stairs, etc.)
- Figure out how to ignore hidden blocks
- Add settings to adjust rotation
- ????? (obviously JavaScript is the defacto standard for these types of projects, but Rust can do web assembly so I guess I could dive into that?)
