A C# console tool for converting rendered Minecraft Java worlds directly into playable CastleMiner Z world folders using native CMZ chunk files and a customizable JSON block map.
This tool converts Minecraft Anvil .mca region chunks into CastleMiner Z native world chunks, such as:
X0Y-64Z0.dat
X16Y-64Z0.dat
X-16Y-64Z32.dat
It can also build a full CastleMiner Z world folder with:
world.info
mc-to-cmz-world.info-check.txt
mc-to-cmz-world.unmapped.txt
X#Y-64Z#.dat
The generated files are written using CastleMiner Z's RTSD SaveDevice wrapper so the game can load them normally from its saved-world list.
- Converts rendered Minecraft Java Edition worlds into CastleMiner Z native chunk
.datfiles. - Reads Minecraft Anvil region files from
.mcafiles. - Supports legacy and modern Minecraft world layouts:
<world>/region<world>/dimensions/minecraft/overworld/region
- Supports configurable Minecraft dimensions, including overworld, Nether, End, and custom datapack dimensions.
- Converts Minecraft block names and block states through a customizable JSON block map.
- Supports modern Minecraft block-state palette packing.
- Supports gzip, zlib, raw-deflate fallback, and uncompressed region chunk payloads.
- Can skip unreadable Minecraft chunks instead of stopping the entire conversion.
- Generates a complete CastleMiner Z world folder with a random UUID folder name.
- Writes CMZ
world.infousing the CastleMiner Z SaveDeviceRTSDwrapper. - Writes CMZ chunk
.datfiles using the CastleMiner Z SaveDeviceRTSDwrapper. - Infers the Steam save key from the CastleMiner Z SteamID save path.
- Supports streaming chunk writes for large worlds without holding the full conversion in RAM.
- Supports explicit vertical Y mapping, such as
Minecraft Y 60 -> CMZ Y -64. - Generates an unmapped block report for missing Minecraft block mappings.
- Windows
- .NET Framework 4.8.1
- CastleMiner Z Steam save folder
- A rendered Minecraft Java Edition world
fNbt.dllSystem.Text.Json.dlland its required dependency DLLs
The converter is currently built as a C# console application.
MCToCMZWorldConverter/
│
├── README.md
├── LICENSE
├── BuildRelease.bat
├── MCToCMZWorldConverter.sln
│
└── MCToCMZWorldConverter/
├── block-map.json
├── config.json
├── ConvertWorldToCMZ.bat
├── MCToCMZWorldConverter.csproj
├── Program.cs
├── Config.cs
│
├── CastleMinerZ/
│ ├── CmzBlockType.cs
│ ├── CmzChunkWriter.cs
│ └── CmzWorldInfoWriter.cs
│
├── Mapping/
│ └── BlockMap.cs
│
├── Minecraft/
│ ├── AnvilWorldReader.cs
│ ├── BigEndianBinaryReader.cs
│ ├── MinecraftChunk.cs
│ ├── MinecraftSection.cs
│ └── RegionFileReader.cs
│
├── Properties/
│ └── AssemblyInfo.cs
│
└── ReferenceAssemblies/
├── fNbt.dll
├── Microsoft.Bcl.AsyncInterfaces.dll
├── System.Buffers.dll
├── System.IO.Pipelines.dll
├── System.Memory.dll
├── System.Numerics.Vectors.dll
├── System.Runtime.CompilerServices.Unsafe.dll
├── System.Text.Encodings.Web.dll
├── System.Text.Json.dll
└── System.Threading.Tasks.Extensions.dll
The converter is config-based:
MCToCMZWorldConverter.exe config.jsonA batch file is included:
ConvertWorldToCMZ.batTypical workflow:
- Open Minecraft and render/explore the world area you want to convert.
- Exit Minecraft.
- Create or locate your CastleMiner Z Steam save folder.
- Edit
config.json. - Run
ConvertWorldToCMZ.bator run the.exewithconfig.json. - Open CastleMiner Z and check the Creative/Infinite Resources world list.
For the Steam version, CastleMiner Z normally stores saves under:
%LOCALAPPDATA%\CastleMinerZ\<SteamID>\Worlds
Example:
C:\Users\John\AppData\Local\CastleMinerZ\76561198296842857\Worlds
OutputCmzWorldFolder should usually point directly to that Worlds folder.
The converter will create a random UUID folder inside it:
Worlds/
b0d30a87-0872-44c5-b77f-8a21459380a7/
world.info
mc-to-cmz-world.info-check.txt
X0Y-64Z0.dat
X16Y-64Z0.dat
...
If your config points one folder above Worlds, set:
"OutputPathIsCastleMinerZSaveRoot": trueExample:
"OutputCmzWorldFolder": "C:/Users/John/AppData/Local/CastleMinerZ/76561198296842857",
"Cmz": {
"OutputPathIsCastleMinerZSaveRoot": true
}The converter will append /Worlds automatically.
By default, the converter creates a new CastleMiner Z world folder:
"CreateWorldFolderWithRandomUuid": trueThis creates:
<Worlds>/<random-guid>/world.info
<Worlds>/<random-guid>/X0Y-64Z0.dat
<Worlds>/<random-guid>/X16Y-64Z0.dat
The generated world.info includes:
WorldInfo version 5
Terrain version CastleMinerZ
Random folder UUID
Random internal WorldID GUID
Random seed unless RandomSeed=false
World name from config
Owner/creator gamertag from config
Empty crates/doors/spawners
Default last position from config
The folder UUID and internal WorldID are intentionally different, matching how CastleMiner Z creates worlds.
CastleMiner Z does not load raw world.info or raw chunk .dat files directly.
Both must be written through the CMZ SaveDevice RTSD wrapper:
world.info -> RTSD wrapped
X0Y-64Z0.dat -> RTSD wrapped
X16Y-64Z0.dat -> RTSD wrapped
For Steam saves, the SaveDevice key is based on your SteamID folder:
MD5(SteamUserID + "CMZ778")
For a path like:
C:\Users\John\AppData\Local\CastleMinerZ\76561198296842857\Worlds
leave this enabled:
"InferSaveDeviceSteamIdFromOutputPath": trueThe converter will infer:
SteamID = 76561198296842857
SaveDevice key = MD5("76561198296842857CMZ778")
To write into an already-created blank CastleMiner Z world folder, set:
"CreateWorldFolderWithRandomUuid": falseThen OutputCmzWorldFolder is treated as the exact CMZ world folder, not the parent Worlds folder.
Example:
"OutputCmzWorldFolder": "C:/Users/John/AppData/Local/CastleMinerZ/76561198296842857/Worlds/b0d30a87-0872-44c5-b77f-8a21459380a7",
"Cmz": {
"CreateWorldFolderWithRandomUuid": false
}Use this mode if you want CastleMiner Z itself to create world.info, then let the converter replace/add the chunk .dat files.
Older Minecraft Java worlds usually store overworld region files here:
<world>/region
Modern/custom-dimension/datapack worlds may store the overworld here:
<world>/dimensions/minecraft/overworld/region
Usually leave RegionFolder blank:
"RegionFolder": ""The converter will auto-detect the best folder based on Dimension and PreferModernDimensionPath.
Overworld:
"Dimension": "minecraft:overworld"Nether:
"Dimension": "minecraft:the_nether"End:
"Dimension": "minecraft:the_end"Custom datapack/modded dimension:
"Dimension": "terralith:some_dimension"This maps to:
<world>/dimensions/terralith/some_dimension/region
You can override auto-detection with a relative path:
"RegionFolder": "dimensions/minecraft/overworld/region"or an absolute path:
"RegionFolder": "C:/Users/John/AppData/Roaming/.minecraft/saves/MyWorld/dimensions/minecraft/overworld/region"The converter reads only the region folder. It does not read Minecraft entities or poi folders.
CastleMiner Z chunks only store 128 vertical block positions:
CMZ Y -64 through CMZ Y 63
Use VerticalMapping to say exactly which Minecraft height should become which CMZ height.
Default:
"VerticalMapping": {
"MinecraftY": 60,
"CmzY": -64
}This means:
Minecraft Y 60 -> CMZ Y -64
Minecraft Y 124 -> CMZ Y 0
Minecraft Y 187 -> CMZ Y 63
So the imported slice is:
Minecraft Y 60..187 -> CMZ Y -64..63
Formula:
CMZ_Y = Minecraft_Y + (CmzY - MinecraftY)
For the default config:
CMZ_Y = Minecraft_Y - 124
Older configs may use:
"CenterY": 124That is equivalent to:
"VerticalMapping": {
"MinecraftY": 60,
"CmzY": -64
}VerticalMapping is recommended because it directly says what height maps to what height.
By default:
"ConvertAllRenderedChunks": trueThis converts every chunk already present in the Minecraft region files.
For a small test conversion, set it to false:
"ConvertAllRenderedChunks": false,
"MinChunkX": -5,
"MaxChunkX": 5,
"MinChunkZ": -5,
"MaxChunkZ": 5The MinChunkX, MaxChunkX, MinChunkZ, and MaxChunkZ values are only used when ConvertAllRenderedChunks=false.
Horizontal offsets can move the converted world inside CastleMiner Z:
"Placement": {
"OffsetX": 0,
"OffsetZ": 0
}When streaming chunk writes are enabled, offsets should be multiples of 16:
Valid: 0, 16, -16, 32, -32
Invalid: 1, 8, 15, 20
This prevents partially-overwritten CMZ chunks.
Default:
"WriteAir": trueThis writes Empty blocks into CMZ so the converted Minecraft terrain replaces the generated CMZ terrain.
If set to false, air is skipped:
"WriteAir": falseSkipping air can be useful for overlay-style conversions, but it will leave existing CMZ terrain in empty spaces.
The Tools/ folder contains helper scripts for maintaining and updating block-map.json.
These tools are not required for normal schematic conversion, but they make it easier to generate Minecraft block id lists and quickly fill large block maps with reasonable CastleMiner Z defaults.
Tools/
├── AutoFillBlockMap.ps1
└── DumpMinecraftBlockIds.bat
DumpMinecraftBlockIds.bat generates a plain text list of Minecraft block ids from Minecraft's extracted blockstates folder.
Minecraft blockstates are stored inside the Minecraft Java Edition client jar at:
assets/minecraft/blockstates
Each .json file in that folder represents one Minecraft block id.
Example:
acacia_log.json -> minecraft:acacia_log
twisting_vines.json -> minecraft:twisting_vines
stone.json -> minecraft:stone
oak_stairs.json -> minecraft:oak_stairs
- Open or extract the Minecraft Java Edition jar you want to support.
Typical jar location:
%APPDATA%\.minecraft\versions\<version>\<version>.jar
- Extract this folder from the jar:
assets\minecraft\blockstates
-
Copy
DumpMinecraftBlockIds.batinto the extractedblockstatesfolder. -
Run the batch file.
The script will create:
minecraft-block-ids.txt
containing entries like:
minecraft:acacia_log
minecraft:twisting_vines
minecraft:stone
minecraft:oak_stairs
Use the newest Minecraft jar when updating the main block-map.json.
Use an older jar only if you specifically want to support or compare against an older Minecraft version.
This tool only dumps base block ids. It does not generate every possible block state combination, such as:
minecraft:oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]
AutoFillBlockMap.ps1 automatically fills blank or existing Minecraft mapping entries with guessed CastleMiner Z block types.
It is useful after generating or expanding block-map.json with a large Minecraft block list.
Example input:
"minecraft:oak_log": "",
"minecraft:oak_leaves": "",
"minecraft:stone": "",
"minecraft:glass": "",
"minecraft:water": ""Example output:
"minecraft:oak_log": "Log",
"minecraft:oak_leaves": "Leaves",
"minecraft:stone": "Rock",
"minecraft:glass": "GlassMystery",
"minecraft:water": "Empty"From the folder containing block-map.json, run:
powershell -ExecutionPolicy Bypass -File .\Tools\AutoFillBlockMap.ps1By default, this reads:
block-map.json
and writes:
block-map.autofilled.json
You can also pass custom paths:
powershell -ExecutionPolicy Bypass -File .\Tools\AutoFillBlockMap.ps1 -InputPath ".\block-map.json" -OutputPath ".\block-map.autofilled.json"Review the generated file before replacing your main block-map.json.
The auto-fill script uses broad name-matching rules. It is designed to create a fast first pass, not a perfect hand-authored map.
For example:
minecraft:oak_stairs -> Wood
minecraft:deepslate -> Rock
minecraft:diamond_ore -> DiamondOre
minecraft:redstone_wire -> Empty
minecraft:white_bed -> Empty
Some Minecraft blocks do not have a clean CastleMiner Z equivalent, so they may need manual adjustment.
Recommended workflow:
- Back up
block-map.json. - Run
AutoFillBlockMap.ps1. - Open
block-map.autofilled.json. - Review important mappings.
- Rename it to
block-map.jsonwhen satisfied.
The block-map.json file controls how Minecraft blocks are converted into CastleMiner Z blocks.
Example:
{
// Default CMZ block used when a Minecraft block is not listed below.
// "Empty" means unmapped blocks become air.
"DefaultBlock": "Empty",
// Minecraft block -> CastleMinerZ block mappings.
"Mappings": {
"minecraft:air": "Empty",
"minecraft:cave_air": "Empty",
"minecraft:void_air": "Empty",
"minecraft:acacia_log": "Log",
"Acacia Log": "Log",
"minecraft:oak_log": "Log",
"minecraft:spruce_log": "Log",
"minecraft:birch_log": "Log",
"minecraft:jungle_log": "Log",
"minecraft:dark_oak_log": "Log",
"minecraft:mangrove_log": "Log",
"minecraft:cherry_log": "Log",
"minecraft:oak_leaves": "Leaves",
"minecraft:spruce_leaves": "Leaves",
"minecraft:birch_leaves": "Leaves",
"minecraft:jungle_leaves": "Leaves",
"minecraft:acacia_leaves": "Leaves",
"minecraft:dark_oak_leaves": "Leaves",
"minecraft:mangrove_leaves": "Leaves",
"minecraft:cherry_leaves": "Leaves",
"minecraft:twisting_vines": "Leaves",
"Twisting Vines": "Leaves",
"minecraft:stone": "Rock",
"minecraft:cobblestone": "Rock",
"minecraft:dirt": "Dirt",
"minecraft:grass_block": "Grass",
"minecraft:sand": "Sand",
"minecraft:snow_block": "Snow",
"minecraft:ice": "Ice",
"minecraft:glass": "GlassBasic",
"minecraft:tnt": "TNT",
"minecraft:torch": "Torch",
"minecraft:chest": "Crate"
}
}The converter normalizes Minecraft block names before lookup.
These can all resolve to the same mapping:
minecraft:acacia_log
acacia_log
Acacia Log
Minecraft block states can also be mapped directly:
{
"Mappings": {
"minecraft:torch[facing=east]": "TorchPOSX",
"minecraft:torch[facing=west]": "TorchNEGX",
"minecraft:torch[facing=north]": "TorchNEGZ",
"minecraft:torch[facing=south]": "TorchPOSZ",
"minecraft:torch": "Torch"
}
}This allows broad mappings and more specific state-based mappings.
When the converter finds Minecraft blocks that are not listed in block-map.json, it writes a report inside the generated CMZ world folder:
mc-to-cmz-world.unmapped.txt
Example contents:
minecraft:polished_andesite
minecraft:oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]
minecraft:lantern[hanging=false,waterlogged=false]
Add missing blocks to block-map.json, then rerun the converter.
When enabled:
"WriteWorldInfoDebugReport": trueThe converter writes:
mc-to-cmz-world.info-check.txt
This report shows:
Generated world folder
WorldInfo version
Terrain version
WorldName
OwnerGamerTag
CreatorGamerTag
CreatedDate
LastPlayedDate
Seed
WorldID
LastPosition
InfiniteResourceMode
SaveDevice key source
RTSD wrapping status
If the world does not appear in CastleMiner Z, check this file first.
This converter handles terrain/block conversion only.
The following Minecraft data is not converted:
- Entities
- Mobs
- Players
- Villagers
- Chests/barrel inventory contents
- Sign text
- Command block data
- Item frames
- Paintings
- Banner patterns
- Redstone behavior
- Waterlogging behavior
- Stairs/fence/wall connection shapes
- Biomes
- Lighting data
- Minecraft height outside the selected 128-block CMZ vertical slice
Some Minecraft blocks do not have a clean CastleMiner Z equivalent and may need manual block-map tuning.
- Back up your CastleMiner Z saves.
- Open Minecraft and render the area you want converted.
- Exit Minecraft.
- Edit
config.json. - Point
InputMinecraftWorldto your Minecraft save folder. - Point
OutputCmzWorldFolderto your actual CastleMiner ZWorldsfolder. - Keep
ConvertAllRenderedChunks=truefor a full conversion, or set it tofalsefor a small test. - Adjust
VerticalMappingif needed. - Run the converter.
- Open CastleMiner Z and load the generated world.
- Review
mc-to-cmz-world.unmapped.txtand updateblock-map.json. - Rerun the converter when needed.
MC to CMZ world conversion
Input MC world: C:\Users\John\AppData\Roaming\.minecraft\saves\CMZ-WORLD-TEST
Output CMZ Worlds folder: C:\Users\John\AppData\Local\CastleMinerZ\76561198296842857\Worlds
Output CMZ world: C:\Users\John\AppData\Local\CastleMinerZ\76561198296842857\Worlds\b0d30a87-0872-44c5-b77f-8a21459380a7
World folder UUID: b0d30a87-0872-44c5-b77f-8a21459380a7
World ID: 30227c27-896c-495b-8cd9-c0aa084220b8
SaveDevice key: inferred SteamID 76561198296842857 from Worlds folder parent
MC region folder: C:\Users\John\AppData\Roaming\.minecraft\saves\CMZ-WORLD-TEST\dimensions\minecraft\overworld\region
Region files: 55
Chunks queued: 37321
Y slice: MC 60..187 -> CMZ -64..63
Y mapping: MC Y 60 -> CMZ Y -64
Write air: True
Keep bedrock: True
Streaming writes: True
Wrap chunks RTSD: True
The project targets:
.NET Framework 4.8.1
Recommended build settings:
Platform: x86
Configuration: Debug or Release
Build with:
BuildRelease.batThe following files should be copied next to the final .exe:
config.json
block-map.json
fNbt.dll
System.Text.Json.dll
System.Memory.dll
System.Buffers.dll
System.Runtime.CompilerServices.Unsafe.dll
System.Text.Encodings.Web.dll
System.Threading.Tasks.Extensions.dll
Microsoft.Bcl.AsyncInterfaces.dll
System.IO.Pipelines.dll
This project is licensed under the GPL-3.0-or-later license.
See LICENSE for details.
Created by RussDev7 for CastleMiner Z / CastleForge tooling.
This project uses fNbt for reading Minecraft NBT/Anvil data.

{ "InputMinecraftWorld": "C:/Users/John/AppData/Roaming/.minecraft/saves/CMZ-WORLD-TEST", // This should point to CMZ's actual Worlds folder. // Example Steam save path: // C:/Users/John/AppData/Local/CastleMinerZ/<SteamID>/Worlds "OutputCmzWorldFolder": "C:/Users/John/AppData/Local/CastleMinerZ/76561198296842857/Worlds", "BlockMap": "block-map.json", "Minecraft": { "ConvertAllRenderedChunks": true, // These bounds are only used when ConvertAllRenderedChunks=false. "MinChunkX": -1, "MaxChunkX": 1, "MinChunkZ": -1, "MaxChunkZ": 1, // Clear vertical mapping. // This says: Minecraft Y 60 becomes CMZ Y -64. "VerticalMapping": { "MinecraftY": 60, "CmzY": -64 }, "Dimension": "minecraft:overworld", "PreferModernDimensionPath": true, "SkipUnreadableChunks": true, "RegionFolder": "" }, "Placement": { "OffsetX": 0, "OffsetZ": 0 }, "AirHandling": { "WriteAir": true }, "Cmz": { "CreateWorldFolderWithRandomUuid": true, "OutputPathIsCastleMinerZSaveRoot": false, "RequireOutputFolderNamedWorlds": true, "WriteWorldInfoDebugReport": true, "InferSaveDeviceSteamIdFromOutputPath": true, "SaveDeviceSteamId": "", "UseCommonSaveDeviceKey": false, "WorldName": "Converted Minecraft World", "OwnerGamerTag": "", "CreatorGamerTag": "", "ServerMessage": "Converted Minecraft World", "ServerPassword": "", "InfiniteResourceMode": true, "RandomSeed": true, "Seed": 0, "LastPositionX": 8.0, "LastPositionY": 128.0, "LastPositionZ": -8.0, "ClearExistingChunkFiles": true, "KeepFloorBedrock": true, "StreamingChunkWrites": true, "WrapChunkFilesWithSaveDevice": true, "OverrideUnmappedBlocks": false, "DefaultUnmappedBlock": "Empty" } }