package catalogs import ( "encoding/json" "os" "path/filepath" "sync" ) var _ = json.RawMessage{} var _ = sync.Mutex{} var _ = os.ReadFile var _ = filepath.Join // One unlockable compendium entry, projected from CityPediaConfig.json. type CityPediaEntry4229938 struct { Id uint32 `json:"id"` Class uint32 `json:"class"` Name string `json:"name"` MaxProgress uint32 `json:"maxProgress"` } // // Build-4229938 city compendium (城市图鉴 / BaiKe) catalog, read from the configured client-data // directory. The source tables do not ship in the v0.3 Configs folder; they come from // 补丁和工具\ConfigDump.zip. Regenerate with _gen_citypedia_cfg.py. // This one IS read by the client, which makes it a much better bet than the quest list was: // lua/LX6/Data/Player/PlayerData/PlayerInfoMinorData.lua // t.playerCityPediaInfos = info.InfoMinor.PlayerCityPediaInfos // lua/LX6/Manager/BaiKeArchiveManager.lua then reads CityPediaStatusDict / CreditInfo off it. // Status is a bit field (UX.Game.CityPediaStatus from the IL2CPP dump): None=0, Unlocked=1, // Read=2. Unlocked|Read (3) is "unlocked and already seen", which also keeps the per-entry red // dot off — CheckCityPediaFirstClassHasRedDot only fires for unlocked-but-unread entries. // const ( // Unlocked | Read. See the class note; change to 1 if the client ever renders // entries as locked (that would mean the decompiled comparisons are not inverted after // all and "Read" is what gates visibility). CityPediaCatalog4229938_StatusUnlockedAndRead byte = 3 ) var ( CityPediaCatalog4229938_cacheLock sync.RWMutex CityPediaCatalog4229938_cached = false CityPediaCatalog4229938_entries []any ) // LoadCityPediaCatalog4229938 loads catalog records from client config directory func LoadCityPediaCatalog4229938(configDir string) ([]any, error) { CityPediaCatalog4229938_cacheLock.RLock() if CityPediaCatalog4229938_cached { defer CityPediaCatalog4229938_cacheLock.RUnlock() return CityPediaCatalog4229938_entries, nil } CityPediaCatalog4229938_cacheLock.RUnlock() CityPediaCatalog4229938_cacheLock.Lock() defer CityPediaCatalog4229938_cacheLock.Unlock() if CityPediaCatalog4229938_cached { return CityPediaCatalog4229938_entries, nil } filePath := filepath.Join(configDir, "CityPediaCatalog.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) } } CityPediaCatalog4229938_entries = result CityPediaCatalog4229938_cached = true return result, nil } func CityPediaCatalog4229938_ReadUInt(row any, prop string) uint32 { // Catalog helper CityPediaCatalog4229938_ReadUInt return 0 } type CityPediaCatalog4229938_Snapshot struct { Entries []CityPediaEntry4229938 `json:"entries"` CreditTypes []uint32 `json:"creditTypes"` MaxLevel uint32 `json:"maxLevel"` MaxLevelValue uint32 `json:"maxLevelValue"` }