135 lines
4.7 KiB
Go
135 lines
4.7 KiB
Go
package catalogs
|
||||
|
|
|
|||
|
|
import (
|
|||
|
|
"encoding/json"
|
|||
|
|
"os"
|
|||
|
|
"path/filepath"
|
|||
|
|
"sync"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
var _ = json.RawMessage{}
|
|||
|
|
var _ = sync.Mutex{}
|
|||
|
|
var _ = os.ReadFile
|
|||
|
|
var _ = filepath.Join
|
|||
|
|
|
|||
|
|
//
|
|||
|
|
// 龙栖村的一个互动摊位机关:打气球 / 套圈 / 刮刮乐 / 五子棋 / 打年糕 …。
|
|||
|
|
// 读自 Configs/MiniGameStalls.json。
|
|||
|
|
//
|
|||
|
|
//
|
|||
|
|
// ★ 为什么需要它(2026-09-27,第 89 轮):
|
|||
|
|
// 这批摊位机关**不在**客户端会自己实例化的清单里。它们的真身有两半:
|
|||
|
|
// ① 客户端 Spoon 图里有一个 GADGET 节点(StartBalloonNode / StartRingTossNode …)
|
|||
|
|
// ② 关卡块里有一份官方世界摆位
|
|||
|
|
// 和 GymEquipment / PartyCamp 完全同因:grid-AOI 下发**不驱动** LX6.Item.GadgetBlob,
|
|||
|
|
// 所以客户端一件都不会自己出现 ⇒ 必须服务端拿 pathId + 官方坐标显式摆一次。
|
|||
|
|
// ★ pathId 空间是「服务端 catalog」那一套(Configs/GadgetCatalog.json,2935 条),
|
|||
|
|
// ⛔ 不是客户端 GadgetConfig.json 的 1367 条(那是另一套 id,
|
|||
|
|
// 例:同一件 Gadget_DaQiQiu 在那边是 79304020,在服务端 catalog 是 912387408)。
|
|||
|
|
// 服务端下发的 pathId 必须取**能被服务端 catalog 查到名字**的那个,否则
|
|||
|
|
// BuildGadgetEntityInfo 会 Warn「not in GadgetCatalog.json」并原样发出。
|
|||
|
|
// ★ 官方世界坐标逐条解自关卡块(工具 gym_tools/_r87_minigame_gadget.py,
|
|||
|
|
// 结果 _r87_minigame_gadget.txt;记录结构 = 命中点 - 28 是记录头,
|
|||
|
|
// +0/+4/+8 = f32 x/y/z,+16 = yaw,+28 = pathId)。
|
|||
|
|
//
|
|||
|
|
type MiniGameStallItem4229938 struct {
|
|||
|
|
PathId int32 `json:"pathId"`
|
|||
|
|
Name string `json:"name"`
|
|||
|
|
X float32 `json:"x"`
|
|||
|
|
Y float32 `json:"y"`
|
|||
|
|
Z float32 `json:"z"`
|
|||
|
|
Yaw float32 `json:"yaw"`
|
|||
|
|
UniqueId uint64 `json:"uniqueId"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 一个摊位片区:一个锚点、一个触发半径,和半径内的摊位机关。
|
|||
|
|
type MiniGameStallSpot4229938 struct {
|
|||
|
|
Name string `json:"name"`
|
|||
|
|
Raid uint32 `json:"raid"`
|
|||
|
|
X float32 `json:"x"`
|
|||
|
|
Z float32 `json:"z"`
|
|||
|
|
Radius float32 `json:"radius"`
|
|||
|
|
Items []MiniGameStallItem4229938 `json:"items"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//
|
|||
|
|
// Reads Configs/MiniGameStalls.json. Tiny file, parsed once behind a Lazy.
|
|||
|
|
// A missing or malformed file is not fatal: the catalog goes empty and
|
|||
|
|
// LoadError explains why, so the caller can log it instead of throwing.
|
|||
|
|
//
|
|||
|
|
var (
|
|||
|
|
MiniGameStallCatalog4229938_cacheLock sync.RWMutex
|
|||
|
|
MiniGameStallCatalog4229938_cached = false
|
|||
|
|
MiniGameStallCatalog4229938_entries []any
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// LoadMiniGameStallCatalog4229938 loads catalog records from client config directory
|
|||
|
|
func LoadMiniGameStallCatalog4229938(configDir string) ([]any, error) {
|
|||
|
|
MiniGameStallCatalog4229938_cacheLock.RLock()
|
|||
|
|
if MiniGameStallCatalog4229938_cached {
|
|||
|
|
defer MiniGameStallCatalog4229938_cacheLock.RUnlock()
|
|||
|
|
return MiniGameStallCatalog4229938_entries, nil
|
|||
|
|
}
|
|||
|
|
MiniGameStallCatalog4229938_cacheLock.RUnlock()
|
|||
|
|
|
|||
|
|
MiniGameStallCatalog4229938_cacheLock.Lock()
|
|||
|
|
defer MiniGameStallCatalog4229938_cacheLock.Unlock()
|
|||
|
|
if MiniGameStallCatalog4229938_cached { return MiniGameStallCatalog4229938_entries, nil }
|
|||
|
|
|
|||
|
|
filePath := filepath.Join(configDir, "MiniGameStallCatalog.json.json")
|
|||
|
|
data, err := os.ReadFile(filePath)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var raw struct {
|
|||
|
|
Records []json.RawMessage `json:"records"`
|
|||
|
|
}
|
|||
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var result []any
|
|||
|
|
for _, item := range raw.Records {
|
|||
|
|
var m map[string]any
|
|||
|
|
if err := json.Unmarshal(item, &m); err == nil {
|
|||
|
|
result = append(result, m)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
MiniGameStallCatalog4229938_entries = result
|
|||
|
|
MiniGameStallCatalog4229938_cached = true
|
|||
|
|
return result, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Spots whose anchor is within <radius> metres of (x, z), nearest first.
|
|||
|
|
func MiniGameStallCatalog4229938_WithinRadius(x float32, z float32, radius float32) []MiniGameStallSpot4229938 {
|
|||
|
|
// Catalog helper MiniGameStallCatalog4229938_WithinRadius
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func MiniGameStallCatalog4229938_Dist2(spot MiniGameStallSpot4229938, x float32, z float32) float32 {
|
|||
|
|
// Catalog helper MiniGameStallCatalog4229938_Dist2
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//
|
|||
|
|
// u64 that the capture script emits as a JSON string (no double round-trip). System.Text.Json
|
|||
|
|
// throws InvalidOperationException ("requires an element of type 'Number'") if you call
|
|||
|
|
// TryGetUInt64 on a string element, so accept both shapes — one bad uid must not kill the file.
|
|||
|
|
//
|
|||
|
|
func MiniGameStallCatalog4229938_U64(source any, name string) uint64 {
|
|||
|
|
// Catalog helper MiniGameStallCatalog4229938_U64
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func MiniGameStallCatalog4229938_Str(source any, name string) string {
|
|||
|
|
// Catalog helper MiniGameStallCatalog4229938_Str
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func MiniGameStallCatalog4229938_Floats(source any, name string, take int32) []float32 {
|
|||
|
|
// Catalog helper MiniGameStallCatalog4229938_Floats
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|