package catalogs import ( "encoding/json" "os" "path/filepath" "sync" ) var _ = json.RawMessage{} var _ = sync.Mutex{} var _ = os.ReadFile var _ = filepath.Join // // 一条 UrbanDiversityPOIActionConfig.json 记录(全字段版 POI 动作)。 // ★ 与既有 DonorPoiActionCatalog4229938(读 PoiActionCatalog.json)的关系: // 两者同一张客户端表(都是 3978 条,Id 一一对应),但那份是裁剪版 // (只有 Id / Name / MainActionGroup / MainActions / UsageId / BelongingSceneItems), // 这份保留了客户端原表的全部字段。本文件是纯新增,不改动、不替换那份, // 现有调用点(Civilians / DonorNpc / FunctionalNpc / Movement / PartyNpc)一行都没动。 // ★ 新增字段能做什么(2026-10-02 对 3978 条做的取值统计,见括号内分布): // // ActionTag3 姿态:站姿 2996 / 坐姿 577 / 蹲姿 80 / 地面躺姿 56 / 躺姿 35 // ⇒ 「让这个 NPC 坐在长椅上」「躺床上」可以按姿态挑动作,不用再靠 MainActions 猜。 // ActionTag1 场景域:大世界 1917 / 重霄大世界 642 / 任务 558 / 室内 468 / 特殊 165 // ⇒ 室内场景只挑「室内」域,避免给室内 POI 派一个露天动作。 // ActionTag2 类型:任务 / 通用 / 运动 / 舞台 / 夜店 // ActionTag4 道具与互动:空 2609 / 道具 763 / 人物互动 270 / 场景互动 106 // ⇒ 需要拿道具的动作(端杯子、用电脑)直接筛 HasProp。 // BehaviorPostureGameplayTag:0 / 34 / 35 / 37 / 38 / 39 —— 姿态的原生 GameplayTag。 // PoiBehaviorType:0(2240) / 1(1595) / 2(143)。 // AgentEmotionTag + AgentEmotionLevel:情绪 1~8 × 强度 1~3 // ⇒ 可以做「心情好的 NPC 挑兴奋度高的动作」这类筛选。 // ExcitementLevel 0~4、ActionFocusLevel 1~5:兴奋度 / 专注档位。 // ApplyRootMotion:370 条 true —— 带根位移的动作(会真的走动), // 挑动作时要考虑会不会把 NPC 从 POI 点位上挪走。 // IsRandomChangeAnimSpeed:37 条 true、IsSpecialPOI:8 条 true。 // // ⛑ 实测下来没有区分度的字段(别在上面投入): // RainPlayable 3978 条全 true(雨天下雨筛选在这张表里筛不出东西); // OccupyGadget / LockGadget 全为 0(物件占用不在这张表里配)。 // ⛑ 加载失败会抛(InvalidDataException)—— 与既有 catalog 一致, // 属于启动期硬失败而不是静默降级。回滚:删本文件 + 删两个 json 即可, // 现有 PoiActionCatalog.json 链路完全不受影响。 // type UrbanDiversityPoiAction4229938 struct { Id uint32 `json:"id"` Name string `json:"name"` MainActionGroup uint32 `json:"mainActionGroup"` MainActions []uint32 `json:"mainActions"` // 场景域:大世界 / 重霄大世界 / 任务 / 室内 / 特殊。 ActionTag1 string `json:"actionTag1"` // 类型:任务 / 通用 / 运动 / 舞台 / 夜店。 ActionTag2 string `json:"actionTag2"` // 姿态:站姿 / 坐姿 / 蹲姿 / 地面躺姿 / 躺姿。 ActionTag3 string `json:"actionTag3"` // 道具与互动:道具 / 人物互动 / 场景互动(可含分号组合)。 ActionTag4 string `json:"actionTag4"` // 专注档位 1~5(0 表示未配)。 ActionFocusLevel uint32 `json:"actionFocusLevel"` // 带根位移 —— true 的动作会让 NPC 真的移动,挑 POI 动作时注意别把它挪离点位。 ApplyRootMotion bool `json:"applyRootMotion"` // 姿态的原生 GameplayTag(0 / 34 / 35 / 37 / 38 / 39)。 BehaviorPostureGameplayTag uint32 `json:"behaviorPostureGameplayTag"` // POI 行为类型 0 / 1 / 2。 PoiBehaviorType uint32 `json:"poiBehaviorType"` // 情绪标签 1~8(3 = 3530 条是默认档)。 AgentEmotionTag uint32 `json:"agentEmotionTag"` // 情绪强度 1~3。 AgentEmotionLevel uint32 `json:"agentEmotionLevel"` // 特殊 POI(仅 8 条)。 IsSpecialPOI bool `json:"isSpecialPOI"` // 随机改变动作播放速度(37 条)。 IsRandomChangeAnimSpeed bool `json:"isRandomChangeAnimSpeed"` // 兴奋度 0~4。 ExcitementLevel uint32 `json:"excitementLevel"` // 雨天是否可播 —— 本表 3978 条全为 true,没有筛选价值。 RainPlayable bool `json:"rainPlayable"` // 物件占用(左 / 右手)—— 本表全为 0,没有筛选价值。 OccupyGadget any `json:"occupyGadget"` // 物件锁定(左 / 右手)—— 本表全为 0。 LockGadget any `json:"lockGadget"` // UsageId(关联 BelongingBelongingUsageConfig 取随身物件),0 = 不带物件。 UsageId uint32 `json:"usageId"` // 动作名(客户端 AnimSet 里的名字,多数为空)。 ActionName string `json:"actionName"` // 动作集名(多数为空)。 ActionSetName string `json:"actionSetName"` // 需要拿道具(ActionTag4 含「道具」)。 HasProp bool `json:"hasProp"` // 需要与人或场景互动(ActionTag4 含「互动」)。 HasInteraction bool `json:"hasInteraction"` } // // UrbanDiversityPOIActionConfig.json 的只读全字段目录(2026-10-02 新增,纯新增不改既有链路)。 // ⛑ 目前没有被任何 handler 引用——先落数据 + 解析器,等要按姿态 / 情绪 / 场景域 // 挑 POI 动作时再接。接的时候推荐用 Where 而不是直接遍历 All。 // var ( UrbanDiversityPoiActionCatalog4229938_cacheLock sync.RWMutex UrbanDiversityPoiActionCatalog4229938_cached = false UrbanDiversityPoiActionCatalog4229938_entries []any ) // LoadUrbanDiversityPoiActionCatalog4229938 loads catalog records from client config directory func LoadUrbanDiversityPoiActionCatalog4229938(configDir string) ([]any, error) { UrbanDiversityPoiActionCatalog4229938_cacheLock.RLock() if UrbanDiversityPoiActionCatalog4229938_cached { defer UrbanDiversityPoiActionCatalog4229938_cacheLock.RUnlock() return UrbanDiversityPoiActionCatalog4229938_entries, nil } UrbanDiversityPoiActionCatalog4229938_cacheLock.RUnlock() UrbanDiversityPoiActionCatalog4229938_cacheLock.Lock() defer UrbanDiversityPoiActionCatalog4229938_cacheLock.Unlock() if UrbanDiversityPoiActionCatalog4229938_cached { return UrbanDiversityPoiActionCatalog4229938_entries, nil } filePath := filepath.Join(configDir, "UrbanDiversityPoiActionCatalog.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) } } UrbanDiversityPoiActionCatalog4229938_entries = result UrbanDiversityPoiActionCatalog4229938_cached = true return result, nil } // 按 Id 查一条。Id 与既有 PoiActionCatalog.json 完全一致(3978 条)。 func UrbanDiversityPoiActionCatalog4229938_TryGet(id uint32, entry UrbanDiversityPoiAction4229938) bool { // Catalog helper UrbanDiversityPoiActionCatalog4229938_TryGet return false } // 按条件筛(姿态 / 情绪 / 场景域 / 是否带道具……)。 func UrbanDiversityPoiActionCatalog4229938_Where(predicate any) []UrbanDiversityPoiAction4229938 { // Catalog helper UrbanDiversityPoiActionCatalog4229938_Where return nil } // // 按姿态筛(ActionTag3):"站姿" / "坐姿" / "蹲姿" / "躺姿" / "地面躺姿"。 // ⛑ 精确匹配;传空串返回「没有配姿态」的那批。 // func UrbanDiversityPoiActionCatalog4229938_ByPosture(posture string) []UrbanDiversityPoiAction4229938 { // Catalog helper UrbanDiversityPoiActionCatalog4229938_ByPosture return nil } // 按场景域筛(ActionTag1):"大世界" / "重霄大世界" / "任务" / "室内" / "特殊"。 func UrbanDiversityPoiActionCatalog4229938_ByDomain(domain string) []UrbanDiversityPoiAction4229938 { // Catalog helper UrbanDiversityPoiActionCatalog4229938_ByDomain return nil } // 按情绪筛(AgentEmotionTag 1~8 + AgentEmotionLevel 1~3)。 func UrbanDiversityPoiActionCatalog4229938_ByEmotion(tag uint32, level uint32) []UrbanDiversityPoiAction4229938 { // Catalog helper UrbanDiversityPoiActionCatalog4229938_ByEmotion return nil } // ⛑ 客户端导出表里同一字段的类型并不稳定(数字可能被写成字符串、布尔可能是 0/1), // 统一走「拿不到就给默认值」而不是抛,避免一条脏数据让整张表加载失败。 func UrbanDiversityPoiActionCatalog4229938_U32(row any, name string) uint32 { // Catalog helper UrbanDiversityPoiActionCatalog4229938_U32 return 0 } func UrbanDiversityPoiActionCatalog4229938_Str(row any, name string) string { // Catalog helper UrbanDiversityPoiActionCatalog4229938_Str return "" } func UrbanDiversityPoiActionCatalog4229938_Bool(row any, name string, fallback bool) bool { // Catalog helper UrbanDiversityPoiActionCatalog4229938_Bool return false } func UrbanDiversityPoiActionCatalog4229938_Pair(row any, name string, left string, right string) any { // Catalog helper UrbanDiversityPoiActionCatalog4229938_Pair var zero any; return zero }