139 lines
5.0 KiB
Go
139 lines
5.0 KiB
Go
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
|
||
}
|
||
|