【文件格式】【傻瓜式】MCEdit存档Schematic格式
本帖最后由 Tao0Lu 于 2020-8-22 20:23 编辑之前帖忘记写Schematic格式了,现在就氵一下吧
其实Wiki里有关于Schematic的格式的介绍,但是我自己通过导出MCEdit发现和Wiki中有些不一样,比如有些项目我导出来并没有,这里我就按我导出的的文件格式讲一下Schematic的格式。
|对象|作用|大小|
|:--|:--|:--|
|Schematic|识别Schematic格式|12字节|
|Height|高度Y 最大64K(mod突破高度限制?)|2字节|
|Length|长度Z 最大64K|2字节|
|Width|宽度X 最大64K|2字节|
|Entities|实体|不固定默认8字节|
|TileEntities|NBT|不固定默认8字节|
|TileTicks|方块要更新的数据|不固定默认8字节|
|Materials|版本 默认Alpha 随意填其他没有事|不固定|
|Data|方块数据 也就是setblock后面那个数字|X × Y × Z字节|
|Biomes|每个方块的生物群系|X × Z字节|
|Block|方块(数字ID, 1. 8及之后可以使用MCEdit-Unified查看)|X × Y × Z字节|
* 如果生物群系对你有作用的话,请看下表
|名称|数字ID|数字ID(16进制)|
|:--|:--|:--|
|海洋|0|0|
|平原|1|1|
|沙漠|2|2|
|山地|3|3|
|森林|4|4|
|针叶林|5|5|
|沼泽|6|6|
|河流|7|7|
|下界荒地|8|8|
|末地|9|9|
|冻洋|10|A|
|冻河|11|B|
|积雪的冻原|12|C|
|雪山|13|D|
|蘑菇岛|14|E|
|蘑菇岛岸|15|F|
|沙滩|16|10|
|沙漠丘陵|17|11|
|繁茂的丘陵|18|12|
|针叶林丘陵|19|13|
|山地边缘|20|14|
|丛林|21|15|
|丛林丘陵|22|16|
|丛林边缘|23|17|
|深海|24|18|
|石岸|25|19|
|积雪的沙滩|26|1A|
|桦木森林|27|1B|
|桦木森林丘陵|28|1C|
|黑森林|29|1D|
|积雪的针叶林|30|1E|
|积雪的针叶林丘陵|31|1F|
|巨型针叶林|32|20|
|巨型针叶林丘陵|33|21|
|繁茂的山地|34|22|
|热带草原|35|23|
|热带高原|36|24|
|恶地|37|25|
|繁茂的恶地高原|38|26|
|恶地高原|39|27|
|末地小型岛屿|40|28|
|末地中型岛屿|41|29|
|末地高岛|42|2A|
|末地荒岛|43|2B|
|暖水海洋|44|2C|
|温水海洋|45|2D|
|冷水海洋|46|2E|
|暖水深海|47|2F|
|温水深海|48|30|
|冷水深海|49|31|
|封冻深海|50|32|
|虚空|127|7F|
|向日葵平原|129|81|
|沙漠湖泊|130|82|
|沙砾山地|131|83|
|繁花森林|132|84|
|针叶林山地|133|85|
|沼泽山丘|134|86|
|冰刺平原|140|8C|
|丛林变种|149|95|
|丛林边缘变种|151|97|
|高大桦木森林|155|9B|
|高大桦木丘陵|156|9C|
|黑森林丘陵|157|9D|
|积雪的针叶林山地|158|9E|
|巨型云杉针叶林|160|A0|
|巨型云杉针叶林丘陵|161|A1|
|沙砾山地+|162|A2|
|破碎的热带草原|163|A3|
|破碎的热带高原|164|A4|
|被风蚀的恶地|165|A5|
|繁茂的恶地高原变种|166|A6|
|恶地高原变种|167|A7|
|竹林|168|A8|
|竹林丘陵|169|A9|
|灵魂沙峡谷|170|AA|
|绯红森林|171|AB|
|诡异森林|172|AC|
|玄武岩三角洲|173|AD|
* 谜?
对于其中的高度限制,我还是不太清楚。虽然说有些Mod可以突破高度限制,但是似乎Mcedit也有高度限制。几次实验后发现如果高度大于255,那么高度好像会从第一行重新写入,也就是说把从第一行已经生成的方块给覆盖掉。如果只有255方块,那么为什么大小要设置成两个字节,难道一个字节不就能用完呢?希望有人能帮我解惑。
* 格式中每个数据(姑且就这么叫吧)之间有指定的字符串去隔开,而在指定的字符串后还要声明此数据的长度。所以每一个数据的格式如下
>指定的分隔字节(两字节)+数据标题长度(一字节)+数据标题+数据长度(+数据)(当为Data,Biomes,Block...时)
|值|识别对象|
|:--|:--|
|0x0A 0x00|Schematic文件|
|0x02 0x00|Height,Length,Width|
|0x09 0x00|Entities,TileEntities,TileTicks|
|0x08 0x00|Materials|
|0x07 0x00|Data,Biomes,Blocks|
* 知道了格式接下来就好做了。
将数据写入文件,再通过同目录下的gzip.exe压缩成x.gz文件,最后重命名为Schematic文件即可用MCEdit打开。
temp(gzip压缩前)
temp(gzip压缩前)
* 那么这里就讲一下data和block数据吧
通过立体坐标计算那么坐标为(X,Y,Z)的方块的data和block数据位于第
> (Y - 1) × (Width × Height) + ( Z - 1) × Width + X
个数据内(Width 和 Height为总的长和宽),只要在这个位置写入Block数据和Data数据就可以了。
**可能你不怎么理解,如果看一下这张图和实例也许就知道了**
* 按X和Z轴来进行,这里有一个5*5的二维平面。我们从第一个方块开始,给每一个方块标记数字。在二维中公式是这样的
>(所在行数-1)×总的列数+所在列数
可见图中红色方块在第5行第4列,代入公式:
>(5-1)×5+4=24 成立
你也可以去试试其他方块,得到的结果是一样的。
其实也能想象得出来,多了一维的情况下,公式变成了这样
>(所在高度-1)×总的行数×总的列数+(所在行数-1)×总的列数+所在列数
## VB代码
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Sub Gen()
....
LoopDB = BmpWidth * BmpHeight * BY '长*宽*高
LoopBI = BmpWidth * BmpHeight '长*宽
TempHX = Replace(Format(Hex(BmpWidth), "@@@@"), " ", "0") '转换成16进制的字符串,以便于写入文件
TempHY = Replace(Format(Hex(BY), "@@@@"), " ", "0")
TempHZ = Replace(Format(Hex(BmpHeight), "@@@@"), " ", "0")
TempHLoopDB = Replace(Format(Hex(LoopDB), "@@@@@@@@"), " ", "0")
TempHLoopBI = Replace(Format(Hex(LoopBI), "@@@@@@@@"), " ", "0")
HX = TempHX
HY = TempHY
HZ = TempHZ
HLoopDB = TempHLoopDB
HLoopBI = TempHLoopBI
ReDim StrDT(LoopDB)
ReDim StrBL(LoopDB)
For Y=1 To BY
For X=1 To BmpWidth
For Z=1 To BmpHeight
StrP = (Y - 1) * (BmpWidth * BmpHeight) + (Z - 1) * BmpWidth+ X '3维方块对应Block和Data数据的位置
StrBL(StrP) = m_Names(Block) '也许用结构体会好点?
StrDT(StrP) = m_Nbt(Block)
'....Block的处理
Next
Next
Next
Open App.Path & "\temp" For Binary As #1 '在当前目录下新建temp文件
Put #1, , Chr$(10) & Chr$(0) & Chr$(9) & "Schematic" '指定的分隔字符串(两字节)+数据标题长度(一字节)+数据标题+数据长度(+数据)
Put #1, , Chr$(2) & Chr$(0) & Chr$(6) & "Height"
Put #1, , CByte("&H" & CStr(Left(HY, 2))) '数据的长度(要以二进制的文件写入)
Put #1, , CByte("&H" & CStr(Right(HY, 2)))
Put #1, , Chr$(2) & Chr$(0) & Chr$(6) & "Length"
Put #1, , CByte("&H" & CStr(Left(HZ, 2)))
Put #1, , CByte("&H" & CStr(Right(HZ, 2)))
Put #1, , Chr$(2) & Chr$(0) & Chr$(5) & "Width"
Put #1, , CByte("&H" & CStr(Left(HX, 2)))
Put #1, , CByte("&H" & CStr(Right(HX, 2)))
Put #1, , Chr$(9) & Chr$(0) & Chr$(8) & "Entities" & Chr$(1) & Chr$(0) & Chr$(0) & Chr$(0) & Chr$(0) & Chr$(9) & Chr$(0) & Chr$(12) & "TileEntities" & Chr$(1) & Chr$(0) & Chr$(0) & Chr$(0) & Chr$(0) & Chr$(9) & Chr$(0) & Chr$(9) & "TileTicks" & Chr$(1) & Chr$(0) & Chr$(0) & Chr$(0) & Chr$(0) & Chr$(8) & Chr$(0) & Chr$(9) & "Materials" & Chr$(0) & Chr$(5) & "Alpha" & Chr$(7) & Chr$(0) & Chr$(4) & "Data"
Put #1, , CByte("&H" & CStr(Left(HLoopDB, 2)))
Put #1, , CByte("&H" & CStr(Mid(HLoopDB, 3, 2)))
Put #1, , CByte("&H" & CStr(Mid(HLoopDB, 5, 2)))
Put #1, , CByte("&H" & CStr(Right(HLoopDB, 2)))
For I = 0 To LoopDB - 1
If Len(StrDT(I)) = 0 Then
Put #1, , Chr$(0)
Else
Put #1, , CByte(StrDT(I)) 'VB的bug?直接Put #1, , StrDT每两个字节之间会多出00
End If
Next
Put #1, , Chr$(7) & Chr$(0) & Chr$(6) & "Biomes"
Put #1, , CByte("&H" & CStr(Left(HLoopBI, 2)))
Put #1, , CByte("&H" & CStr(Mid(HLoopBI, 3, 2)))
Put #1, , CByte("&H" & CStr(Mid(HLoopBI, 5, 2)))
Put #1, , CByte("&H" & CStr(Right(HLoopBI, 2)))
For I = 0 To LoopBI - 1
Put #1, , Chr$(0)
Next
Put #1, , Chr$(7) & Chr$(0) & Chr$(6) & "Blocks"
Put #1, , CByte("&H" & CStr(Left(HLoopDB, 2)))
Put #1, , CByte("&H" & CStr(Mid(HLoopDB, 3, 2)))
Put #1, , CByte("&H" & CStr(Mid(HLoopDB, 5, 2)))
Put #1, , CByte("&H" & CStr(Right(HLoopDB, 2)))
For I = 0 To LoopDB - 1
If Len(StrBL(I)) = 0 Then
Put #1, , Chr$(0)
Else
Put #1, , CByte(StrBL(I))
End If
Next
Put #1, , Chr$(0)
Close #1
OutPut
End Sub
Private Sub OutPut()
Dim Path As String
Dim I As Long, R As Long, P As Long
Path = SaveFile()'文件对话框,这里不多讲了,此时Path已经成为一个Schematic的目录
I = Shell(App.Path & "\gzip.exe -f """ & App.Path & "\temp""", vbNormalFocus) '调用Gzip压缩(输出为.gz文件)
P = OpenProcess(SYNCHRONIZE, False, I) '等待进程(文件都没有生成怎么进行下一步啊喂)
R = WaitForSingleObject(P, INFINITE)
R = CloseHandle(P)
I = Shell("cmd /c copy """ & App.Path & "\temp.gz"" " & Path & " /y", vbNormalFocus)'重命名成.Schematic文件
P = OpenProcess(SYNCHRONIZE, False, I)
R = WaitForSingleObject(P, INFINITE)
R = CloseHandle(P)
I = Shell("cmd /c del /f /q """ & App.Path & "\temp.gz""", vbNormalFocus)'删除Temp
P = OpenProcess(SYNCHRONIZE, False, I)
R = WaitForSingleObject(P, INFINITE)
R = CloseHandle(P)
End Sub
## 注意
* 在VB写入文件时,方块等数据不能使用Chr,这是因为当Chr的Acsii编码超过128的都会被翻译成"?",所以需要通过写入Binary文件,调用CByte来写入文件。
* 除数据标题以外以上数据都以二进制的方式写入文件。
* 数据可以调换顺序。
同为邯郸老乡在线支持大佬! watermelon 发表于 2020-3-21 19:09
同为邯郸老乡在线支持大佬!
? 话说这个不是显示自己所在的IP吗,或者我发布的时候魔法上网了? Tao0Lu 发表于 2020-3-21 19:17
? 话说这个不是显示自己所在的IP吗,或者我发布的时候魔法上网了?
哦,哈哈哈,我是看的地下的那个签名图片上的“Network”项的,应该是根据IP地址写出来的所在地。
页:
[1]