こんにちは、ラルフです。

前回の投稿 で触れなかった技術面的なものを紹介したいなと思います。

上の投稿のWSでは、Minecraft Educationを使用し、熊本城の建築もWin10Beta版で行いました。

しかし、途中にMinecraft Edu (Java版のMinecraftと中身は同じ)を使うかもしれないという話を受け、急遽ワールドを変換しなければいけないという自体が発生しました。

前提知識としては、Minecraft EducationとMinecraft Windows 10 Betaはmcworld形式(PEバージョンなどと互換性がある方式です)でワールドの書き出しができます。

Java版のワールドは、Anvil形式というワールドの保存形式が使われています。

もちろん互換性はまったくなく、変換するツールが有償で配布されていたりもしたのですが、確実に変換できる保証がないためコンバーターを作成しました。

こちらです。

現状はmcworld→pcの1方向しか変換ができません。

また、ブロックの変換しか出来ないという制限や、変換されたワールドが1.7上で読み込むと不安定というバグもあります。

内部のプロセスや形式周りについて話していきたいと思います。

mcworld形式のファイルは単純なzipファイルで、拡張子を変えてあげれば解凍することが出来ます。

内部にはlevel.datなどがあり、zipファイル内のdbフォルダがワールドデータが格納されているフォルダになります。

このdbフォルダ全体でLevelDBというファイル形式であり、Googleが開発したものらしいです。

しかし、本家のものからzlibでの圧縮ができるように改変されたものらしく、こちらのリポジトリでC++用のコードが見れます。

Javaでの実装もしっかりと作っている方がいたので、そちらを使います。

LevelDBはKeyValue型のデータを格納することが出来、Keyの中に「どのチャンクのどのようなデータか」という情報が入っています。

手順としては、全てのKeyValueのペアに対してループを回し、ブロックの情報を格納しているペアだけを次の処理に回す形です。

Keyは9バイトのデータであり、先頭4バイトがチャンクのx座標、次の4バイトがチャンクのz座標、最後1バイトがどのデータかの数値となっています。

ブロックデータを保存しているペアのとき、Valueは83220バイトのデータであり、先頭32768バイトがブロックデータ(1ブロック1バイトで16*16*128個、データは符号なし整数でブロックIDと同じ数字になる)となります。

次の16384バイトがRegular dataというセクションで、いわゆるブロックのメタデータとなります。1バイトの中で先頭4bit、後方4bitで別々のブロックのメタデータを表します。

同じように次の16384バイトがSkylight dataというセクションで、イマイチ使用用途が読めませんでした(おそらく太陽光と何かしら関係しているはずですが・・・)

次の16384バイトがブロックのライトレベルに関するデータです。

更に256バイトと1024バイトのセクションもあるっぽいですが、今回の変換では使いませんでした。

PC側では、ワールドデータの生成にJ2Blocksを使用したので、細かな仕様は気にせずに行うことが出来ました。

こういったライブラリが既にあるというのは非常に助かりました。

変換作業の中で一番混乱した点は、mcworld側のBlockIDとJava側のBlockIDが違うものがあるという点です。

例えば、WoodenSlab(木のハーフブロックは)mcworldだと158番ですが、Java版において158番はピストンになっているため、Java版におけるWoodenSlabのIDである126番に変換してあげなければいけません。

また、LevelDBのKeyとなっているChunkのx,zのバイト列はリトルエンディアンのため、注意が必要です。

このような注意点はありましたが、なんとか問題なく変換は行えるようになっています。

(書き出したJavaワールドは不安定なため、1.10のWorldEditで建物部分だけschematicファイルに変換し、新規生成した安定したワールドにペーストする形を取った)

(また、WSでは結局Educationを使用したので、ツールの出番はなかった)

双方向のワールド変換が安定的にできるようになれば、配布ワールドのデータをEducationで使用するなど、大規模なワールドを利用しやすくなるため、今後必要になるのではないかなと考えています。

逆方向も作っている最中なので、完成したらまた記事でも書こうかなと思います。

では