0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【統合版マイクラ】スーパーフラット解析してみた

Last updated at Posted at 2025-12-06

すーみそー
sumiso_c0db8cだ。

統合版マイクラ、スーパーフラットワールドの設定ファイルlevel.datを解析して
オリジナルのスーパーフラットを作成してみた。

本記事は統合版マイクラ 1.21.124で動作確認を行いました。

先行研究

「クラフターズコロニー」さんではカスタムフラットジェネレーターを公開されています。
https://minecraft-mcworld.com/custom-flat/

ソースコードはGitHubにてMITライセンスで提供されています。こちらを参考にしました。

level.dat取得

適当なスーパーフラットのワールドをマイクラで作成し、level.datを取得します。

マイクラでスーパーフラットのワールドを生成します。
スーパーフラット

セーブデータより、level.datを取得します。

ファイルの場所
%APPDATA%\Minecraft Bedrock\Users\[ユーザーのid]\games\com.mojang\minecraftWorlds\[ワールドのフォルダ]\level.dat

エクスプローラーで%APPDATA%\Minecraft Bedrock\Users\にアクセスすると数字のフォルダがあるため
そこからたどっていくのがオススメです。

ワールドのフォルダ名は謎の英字記号の組み合わせで、どのワールドか分かりません。
開いてworld_icon.jpegをみれば、ワールド選択画面の画像を確認できます。

level.dat解析

level.datファイルはバイナリデータのため、メモ帳などの普通のテキストエディタでは開けません。jupyter notebook上でpythonを利用して解析していきます。

環境構築はこちら。

pythonでのバイナリデータ操作の解説はこちらの記事をご参照ください。

ファイル読み込み

バイナリデータを読み込みます。

filepath = 'level.dat'
# ファイルを読み込む
with open(filepath, 'rb') as f:
    data = f.read()
data
出力
b'\n\x00\x00\x00\...(以下略)

bytesオブジェクトが文字列表現で出力されます。こちらをテキストファイルにコピペして保存します。以下このファイルから該当部分を目視でコピペし、解析しています。

シード値

シード値が正の値の場合、RandomSeedに続く8バイトのデータがシード値を表しています。
この部分をコピペしてデコードします。
RandomSeed\x8d\x00\x00\x00\x00\x00\x00\x00

import struct
seed_bytes = b'\x8d\x00\x00\x00\x00\x00\x00\x00'

seed = struct.unpack('<q', seed_bytes)[0]
print(f"シード値: {seed}")
出力
シード値: 141

ワールド名

LevelName直後の2バイトがワールド名の長さを表し
その次がワールド名本体です。

LevelName\x1e\x00sumiso\xe3\x82\xb9\xe3\x83\xbc\xe3\x83\x91\xe3\x83\xbc\xe3\x83\x95\xe3\x83\xa9\xe3\x83\x83\xe3\x83\x88

name_length = struct.unpack('<H', b'\x1e\x00')[0]
print(f"ワールド名の長さ:{name_length}バイト")
出力
ワールド名の長さ:30バイト
name_bytes = b'sumiso\xe3\x82\xb9\xe3\x83\xbc\xe3\x83\x91\xe3\x83\xbc\xe3\x83\x95\xe3\x83\xa9\xe3\x83\x83\xe3\x83\x88'
level_name = name_bytes.decode('utf-8')
print(f"ワールド名: {level_name}")
出力
ワールド名: sumisoスーパーフラット

地形の設定

FlatWorldLayers直後の2バイトが地層の定義の長さを表し
続けて地層の定義がjson形式で記載されています。

FlatWorldLayers\xfb\x00{フラットワールドの地層}

地層の定義をフォーマットしたものがこちら

{
    "biome_id": 1,
    "block_layers": [
        {
            "block_name": "minecraft:bedrock",
            "count": 1
        },
        {
            "block_name": "minecraft:dirt",
            "count": 2
        },
        {
            "block_name": "minecraft:grass_block",
            "count": 1
        }
    ],
    "encoding_version": 6,
    "preset_id": "ClassicFlat",
    "world_version": "version.post_1_18"
}

biome_idはwikiに記載があります。
https://minecraft.wiki/w/Biome#Bedrock_Edition
1は平原バイオームです。

block_nameはコマンドでブロックを指定するときの名前です。

world_versionは1.18の洞窟と崖のアップデートでの地形生成ルール大幅変更後、かと思われます。

level.dat生成

以上の解析を踏まえて、これらの値を書き換えてlevel.datを再構築
オリジナルスーパーフラットを作成してみました。

テンプレート作成

解析したlevel.datをテンプレートとし、値を書き換えます。
変更のない部分のバイナリデータをコピーし、部分ごとに定義しておきます。

head = b'\(ファイルの最初から)FlatWorldLayers'

after_FlatWorldLayers = b'\n\x01(中略)LevelName'

after_LevelName = b'\x03\x13\x00(中略)RandomSeed'

after_seed = b'\x01\x10\x00SpawnV1Villagers(ファイルの最後まで)'

地形の設定

地形をお好みで書き換えます。

import json
# JSON構築
flat_json = {
    "biome_id": 5,
    "block_layers": [
        {
            "block_name": "minecraft:bedrock",
            "count": 1
        },
        {
            "block_name": "minecraft:gray_concrete",
            "count": 63
        },
        {
            "block_name": "minecraft:gray_concrete",
            "count": 100
        }
    ],
    "encoding_version": 6,
    "preset_id": None,
    "world_version": "version.post_1_18"
}
json_str = json.dumps(flat_json,separators=(',', ':'),)
json_bytes = json_str.encode('utf-8')
json_len = len(json_bytes) + 1

# 2バイトの長さ情報(リトルエンディアン)
json_header = struct.pack('<H', json_len)

バイオームはタイガ、灰色のコンクリートを高さ100まで敷き詰めます。
"preset_id": Noneにしておかないとクラシックフラットが爆誕します。
jsonはスペースを入れずに詰めて作成し、長さを+1します。

シード値

シード値を変換します。

seed = 141
seed_bytes = struct.pack('<q', seed)

ワールド名

ワールド名と長さ情報のバイナリデータを生成します。

world_name = 'sumiso creative テンプレート'
world_name_bytes = world_name.encode('utf-8')
world_name_len_bytes = len(world_name_bytes).to_bytes(2, 'little')

データ結合

作成したバイナリデータを結合します。結合したバイナリデータを元に、ファイルサイズを取得、ヘッダー部に上書きします。

# バイナリ結合
binary = head + json_header + json_bytes + after_FlatWorldLayers + world_name_len_bytes + world_name_bytes + after_LevelName + seed_bytes + after_seed

# ファイルサイズをヘッダーに上書き
file_size = len(binary) - 8
file_size_bytes = struct.pack('<I', file_size)
binary = binary[:4] + file_size_bytes + binary[8:]
binary

mcworld生成

level.datを生成、マイクラにインポートできるようにmcworld形式にまとめます。

import zipfile
import os

# 1. level.dat を保存
with open("level.dat", "wb") as f:
    f.write(binary)

# 2. ZIPファイルに圧縮(level.dat を含む)
with zipfile.ZipFile("world.zip", "w", zipfile.ZIP_DEFLATED) as zipf:
    zipf.write("level.dat")

# 3. ZIPファイルを .mcworld にリネーム
os.rename("world.zip", "sumiso_world.mcworld")

動作確認

作成したmcworldをマイクラにインポートします。

オリジナルスーパーフラット

灰色のコンクリートのスーパーフラット、高さ100ができました。これでスライムチャンク湧きのスライムに悩まされることはありません。

バイオーム確認
草ブロックの色合いはタイガらしくなっています。

まとめ

本記事では、統合版マイクラのlevel.datファイルをpythonで解析し、オリジナルスーパーフラットを生成してみました。
level.dataには他にも様々な設定値が定義されています。バイナリデータを読み解く自信のある方は解析に挑戦してみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?