package catalogs import ( "encoding/json" "os" "path/filepath" "sync" ) var _ = json.RawMessage{} var _ = sync.Mutex{} var _ = os.ReadFile var _ = filepath.Join // // One challenge row, projected from ChallengeConfig.json by _gen_challenge_cfg.py. // Only the id is strictly required by the wire contract — the client reads its own // ChallengeConfig for names / counters / rewards — but Tag and Type // are kept so the login fill can be scoped later (e.g. publish only 赛车挑战 201) without // regenerating the table. // type ChallengeEntry4229938 struct { Id uint32 `json:"id"` Name string `json:"name"` Tag uint32 `json:"tag"` Type uint32 `json:"type"` Image uint32 `json:"image"` Job uint32 `json:"job"` JobLevel uint32 `json:"jobLevel"` Pre uint32 `json:"pre"` } // // Build-4229938 challenge catalog (T0-2). The source table is ChallengeConfig.json, which does not // ship in the v0.3 Configs folder; it comes from 补丁和工具\ConfigDump.zip. Regenerate with // _gen_challenge_cfg.py. // Both challenge dictionaries travel in the login payload and the client does read them: // lua/LX6/Data/Player/PlayerData/PlayerInfoAchievementData.lua:12-13 // t.ChallengeRecordInfo = info.InfoAchievement.ChallengeRecordInfo // t.NewChallengeRecordInfo = info.InfoAchievement.NewChallengeRecordInfo // ⛑⛑ The two are dictionaries, not lists — authoritative shape from // lua/LuaGen/AutoGen/RPCDeserializeAuto.lua (Auto.Reader[1305]): // ChallengeRecordInfo = ReadDict7Bit(u32 key -> Complex(Reader[381])) // NewChallengeRecordInfo = ReadDict7Bit(u32 key -> Complex(Reader[594])) // The only other place ChallengeRecordInfo appears is GameToClientImpl.lua:1099 // (SyncCompletedChallenge), which does table.insert(...) on it — appending an *integer* key into // the dictionary after login. That is a separate S2C channel and a client-side quirk; it does not // change the dictionary shape the login payload has to emit. // var ( ChallengeCatalog4229938_cacheLock sync.RWMutex ChallengeCatalog4229938_cached = false ChallengeCatalog4229938_entries []any ) // LoadChallengeCatalog4229938 loads catalog records from client config directory func LoadChallengeCatalog4229938(configDir string) ([]any, error) { ChallengeCatalog4229938_cacheLock.RLock() if ChallengeCatalog4229938_cached { defer ChallengeCatalog4229938_cacheLock.RUnlock() return ChallengeCatalog4229938_entries, nil } ChallengeCatalog4229938_cacheLock.RUnlock() ChallengeCatalog4229938_cacheLock.Lock() defer ChallengeCatalog4229938_cacheLock.Unlock() if ChallengeCatalog4229938_cached { return ChallengeCatalog4229938_entries, nil } filePath := filepath.Join(configDir, "ChallengeCatalog.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) } } ChallengeCatalog4229938_entries = result ChallengeCatalog4229938_cached = true return result, nil } func ChallengeCatalog4229938_UInt(row any, name string) uint32 { // Catalog helper ChallengeCatalog4229938_UInt return 0 }