package catalogs import ( "encoding/json" "os" "path/filepath" "sync" ) var _ = json.RawMessage{} var _ = sync.Mutex{} var _ = os.ReadFile var _ = filepath.Join // One party-camp prop the server places itself (grill / tent / bonfire / mat / lamp…). type PartyCampItem4229938 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"` } // One party venue's camp: the official PartySpot anchor, a trigger radius, its props. type PartyCampSite4229938 struct { Name string `json:"name"` PartyId uint32 `json:"partyId"` Raid uint32 `json:"raid"` X float32 `json:"x"` Y float32 `json:"y"` Z float32 `json:"z"` Rotation float32 `json:"rotation"` Radius float32 `json:"radius"` Items []PartyCampItem4229938 `json:"items"` } // // Reads Configs/PartyCamp.json — the official campground furniture (露营家具) for each party venue. // // // WHY THIS FILE EXISTS (2026-09-26, round 44) // ------------------------------------------- // 用户在游戏里站在露营点 2.8 m 处实测「家具全无」——烤炉、帐篷、篝火、野餐垫一件都没有。 // 他问的那句「是不是和健身器材一样」是**对的**:这批 `Gadgets_Party_*` 和 `wodegym_*` 同类, // 客户端不会自己把 blob 里的它们实例化出来(grid-AOI 下发 68956797 不驱动 // `GadgetBlob.OnAoiAddBlobCfgByGridIndex`),必须服务端用 SyncGadgetAdd 显式摆。 // ★ 关键判据(回答「是不是开派对才刷」):**不是**。 // 1. 这套家具烘焙在**主城 free-roam 副本 23300888** 的关卡数据里(记录前挂着 raid 字符串 // `23300888` 与实例键 `23300888_60000023_60000023`),不是派对专用副本; // 2. 露营/舞会的 `PartyConfig.RaidId` 就是 23300888 —— **派对是就地举行,不切副本**, // 所以场地家具只能是预先烘焙在开放世界里的; // 3. 营地 400 m 圈内是改车店 / 公共厕所 / 时装店 / 象棋摊 / wodegym 等**主城常驻机关** // ⇒ 营地就是主城里的一块地,不是单独场景; // 4. 同一批 prefab(`Gadgets_Party_BBQGrill`)还被当作**天台夜市**的常驻装点摆在 // (-378.28, 130.50, -497.87),那一处与任何派对点位无关。 // ⇒ 所以服务端应当**按场地坐标常驻摆放**,而不是「开派对时才摆」。 // 坐标来源:逐条解自关卡块 `Blocks/vfc_1479` 的 88 B 机关摆位表(pathId 在记录头 +28, // 记录头 = pathId 命中点 - 28)。同一套家具在块里被 3~4 张表各列一遍(顺序与个别 y 略有差异), // PartyCamp.json 只取**带 raid 实例键的那一张**。生成脚本 `gym_tools/_camp_list.py`。 // 缺失/损坏不致命:表空 + LoadError 说明原因,调用方跳过即可。 // var ( PartyCampCatalog4229938_cacheLock sync.RWMutex PartyCampCatalog4229938_cached = false PartyCampCatalog4229938_entries []any ) // LoadPartyCampCatalog4229938 loads catalog records from client config directory func LoadPartyCampCatalog4229938(configDir string) ([]any, error) { PartyCampCatalog4229938_cacheLock.RLock() if PartyCampCatalog4229938_cached { defer PartyCampCatalog4229938_cacheLock.RUnlock() return PartyCampCatalog4229938_entries, nil } PartyCampCatalog4229938_cacheLock.RUnlock() PartyCampCatalog4229938_cacheLock.Lock() defer PartyCampCatalog4229938_cacheLock.Unlock() if PartyCampCatalog4229938_cached { return PartyCampCatalog4229938_entries, nil } filePath := filepath.Join(configDir, "PartyCampCatalog.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) } } PartyCampCatalog4229938_entries = result PartyCampCatalog4229938_cached = true return result, nil } // Camp sites whose anchor is within metres of (x, z). func PartyCampCatalog4229938_WithinRadius(x float32, z float32, radius float32) []PartyCampSite4229938 { // Catalog helper PartyCampCatalog4229938_WithinRadius return nil } func PartyCampCatalog4229938_Dist2(site PartyCampSite4229938, x float32, z float32) float32 { // Catalog helper PartyCampCatalog4229938_Dist2 return 0 } // // u64 written as a JSON string (no double round-trip). TryGetUInt64 throws on a String element, // so accept both shapes — one bad uid must not kill the file. // func PartyCampCatalog4229938_U64(source any, name string) uint64 { // Catalog helper PartyCampCatalog4229938_U64 return 0 } func PartyCampCatalog4229938_Str(source any, name string) string { // Catalog helper PartyCampCatalog4229938_Str return "" } func PartyCampCatalog4229938_Floats(source any, name string, take int32) []float32 { // Catalog helper PartyCampCatalog4229938_Floats return nil }