- UID
- 3517
- 精华
- 积分
- 959
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
本帖最后由 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压缩前)
-
那么这里就讲一下data和block数据吧
通过立体坐标计算那么坐标为(X,Y,Z)的方块的data和block数据位于第
(Y - 1) × (Width × Height) + ( Z - 1) × Width + X
个数据内(Width 和 Height为总的长和宽),只要在这个位置写入Block数据和Data数据就可以了。
可能你不怎么理解,如果看一下这张图和实例也许就知道了
- 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来写入文件。
- 除数据标题以外以上数据都以二进制的方式写入文件。
- 数据可以调换顺序。
|
|