技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 343|回复: 3
收起左侧

【文件格式】【傻瓜式】MCEdit存档Schematic格式

[复制链接]

11

主题

46

帖子

727

积分

用户组: 大·技术宅

UID
3517
精华
0
威望
20 点
宅币
623 个
贡献
18 次
宅之契约
0 份
在线时间
155 小时
注册时间
2018-3-2
发表于 2020-3-16 22:51:01 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有帐号?立即注册→加入我们

x
本帖最后由 Tao0Lu 于 2020-3-17 07:24 编辑

        之前帖忘记写Schematic格式了,现在就氵一下吧

        其实Wiki里有关于Schematic的格式的介绍,但是我自己通过导出MCEdit发现和Wiki中有些不一样,比如有些项目我导出来并没有,这里我就按我导出的的文件格式讲一下Schematic的格式。
       071330stmb000n2tftm902.jpg
        如果生物群系对你有作用的话,请看下表 :
       172500zo91o80qqo9hww08.png

      谜?
              对于其中的高度限制,我还是不太清楚。虽然说有些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打开。

        Schematic(gzip压缩后)
        1.png

        temp(gzip压缩前)
        2.png

               那么这里就讲一下data和block数据吧
               通过立体坐标计算那么坐标为(X,Y,Z)的方块的data和block数据位于第
              (Y - 1) * (Width * Height) + ( Z - 1) * Width + X
               个数据内(Width 和 Height为总的长和宽),只要在这个位置写入Block数据和Data数据就可以了。

               可能你不怎么理解,如果看一下这张图和实例也许就知道了
               174118dhgu1gnbnq8o659g.png
               按X和Z轴来进行,这里有一个5*5的二维平面。我们从第一个方块开始,给每一个方块标记数字。在二维中公式是这样的
              (所在行数-1)*总的列数+所在列数
               可见图中红色方块在第5行第4列,代入公式:
              (5-1)*5+4=24 成立
             你也可以去试试其他方块,得到的结果是一样的。
             其实也能想象得出来,多了一维的情况下,公式变成了这样
              (所在高度-1)*总的行数*总的列数+(所在行数-1)*总的列数+所在列数

[Visual Basic] 纯文本查看 复制代码
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来写入文件。
        除数据标题以外以上数据都以二进制的方式写入文件。
        数据可以调换顺序。







评分

参与人数 2威望 +20 宅币 +40 贡献 +11 收起 理由
0xAA55 + 10 + 10 + 1 屌!
watermelon + 10 + 30 + 10 厉害了!

查看全部评分

回复

使用道具 举报

24

主题

261

帖子

1493

积分

用户组: 上·技术宅

UID
3808
精华
6
威望
53 点
宅币
1006 个
贡献
90 次
宅之契约
0 份
在线时间
261 小时
注册时间
2018-5-6
发表于 2020-3-21 19:09:21 | 显示全部楼层
同为邯郸老乡在线支持大佬!
菜鸟一枚,直接指正,不必留情

11

主题

46

帖子

727

积分

用户组: 大·技术宅

UID
3517
精华
0
威望
20 点
宅币
623 个
贡献
18 次
宅之契约
0 份
在线时间
155 小时
注册时间
2018-3-2
 楼主| 发表于 2020-3-21 19:17:25 | 显示全部楼层
watermelon 发表于 2020-3-21 19:09
同为邯郸老乡在线支持大佬!

? 话说这个不是显示自己所在的IP吗,或者我发布的时候魔法上网了?

24

主题

261

帖子

1493

积分

用户组: 上·技术宅

UID
3808
精华
6
威望
53 点
宅币
1006 个
贡献
90 次
宅之契约
0 份
在线时间
261 小时
注册时间
2018-5-6
发表于 2020-3-21 19:19:37 | 显示全部楼层
Tao0Lu 发表于 2020-3-21 19:17
? 话说这个不是显示自己所在的IP吗,或者我发布的时候魔法上网了?

哦,哈哈哈,我是看的地下的那个签名图片上的“Network”项的,应该是根据IP地址写出来的所在地。
菜鸟一枚,直接指正,不必留情

本版积分规则

QQ|申请友链||Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图  

GMT+8, 2020-7-10 18:09 , Processed in 0.098530 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表