first release

This commit is contained in:
tamakyi
2026-09-18 13:05:49 +08:00
commit b327bc1230
123 changed files with 30003 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
package fog
import (
"archive/zip"
"bytes"
"fmt"
"io"
"path"
"strings"
)
// layerMaxBytes 是单个留存条目的解压上限(实测最大约 250KB)。
const layerMaxBytes = 8 << 20
// RawLayers 取出快照里「不属于已探索层」的条目(内容原样,条目名也原样)。
//
// fog of world 的快照里有三类瓦片:
//
// Model/* 已探索层:128×128 块,每块 512 字节位图 + 3 字节元信息(本包解析的就是它)
// Model/~ 另一层位图:每块 512 字节,没有那 3 字节
// Model/# 只有元信息:每块 3 字节
//
// 后两类我们不解析(站点只用已探索层来渲染),但**必须原样留住**——
// 否则重新导出的快照会丢掉这 55% 的内容,fog of world 那边看到的就是残缺数据。
//
// 留存范围是「快照里的全部条目,除去已探索层与被 Decode 解析掉的那些瓦片」:
// Decode 认的是「文件名能通过瓦片校验」,不认目录,所以判断也要按文件名来,
// 否则同一个文件会被解析一遍、又原样写一遍,包里出现两份。
func RawLayers(data []byte) (map[string][]byte, error) {
zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
return nil, err
}
out := map[string][]byte{}
for _, f := range zr.File {
if f.FileInfo().IsDir() {
continue
}
p := path.Clean(strings.ReplaceAll(f.Name, "\\", "/"))
// Model/* 之下就是已探索层,由 fog_blocks 重建
if rest := strings.TrimPrefix(p, "Model/"); rest != p {
if i := strings.Index(rest, "/"); i > 0 && rest[:i] == "*" {
continue
}
}
// 文件名能通过瓦片校验的会被 Decode 解析成块,写回时也走 Model/*,这里不重复留存
if _, ok := tileIDFromName(path.Base(p)); ok {
continue
}
rc, err := f.Open()
if err != nil {
return nil, err
}
// 留存的条目不解析、也不该被截断:超限就报错,别把半份数据悄悄带进导出包
raw, err := io.ReadAll(io.LimitReader(rc, layerMaxBytes+1))
rc.Close()
if err != nil {
return nil, err
}
if int64(len(raw)) > layerMaxBytes {
return nil, fmt.Errorf("条目 %s 超过 %d 字节,疑似异常快照", p, layerMaxBytes)
}
out[p] = raw
}
return out, nil
}