package catalogs import ( "encoding/json" "os" "path/filepath" "sync" ) var _ = json.RawMessage{} var _ = sync.Mutex{} var _ = os.ReadFile var _ = filepath.Join // One league (C级赛 / B级赛) and the groups it is made of. type RacingCompetition4229938 struct { Id uint32 `json:"id"` Category string `json:"category"` GroupIds []uint32 `json:"groupIds"` } // // One league group. The gate is authored: a group opens when it is not hard-locked and the player // has reached both thresholds. Group 1 is 0/0, so a fresh player starts there. // type RacingCompetitionGroup4229938 struct { Id uint32 `json:"id"` IsLocked bool `json:"isLocked"` UnlockPoint uint32 `json:"unlockPoint"` UnlockStar uint32 `json:"unlockStar"` TrackIds []uint32 `json:"trackIds"` } // One track. MaxPlayers == 0 means an authored row that is not actually playable. type RacingTrack4229938 struct { Id uint32 `json:"id"` MaxPlayers uint32 `json:"maxPlayers"` } // // Reads the three authored racing tables for the 赛车手 phone app: // RacingDriverCompetitionConfig.json (2 leagues: C级赛 / B级赛), // RacingDriverCompetitionGroupConfig.json (3 groups) and // RacingDriverTrackInformationConfig.json (24 tracks). // The client owns the same tables, so the server only reads the ids and the unlock gates — it never // invents progress. A missing or malformed file degrades to "no leagues" instead of throwing, so a // broken config cannot break LoginGame or the app. // var ( RacingCatalog4229938_cacheLock sync.RWMutex RacingCatalog4229938_cached = false RacingCatalog4229938_entries []any ) // LoadRacingCatalog4229938 loads catalog records from client config directory func LoadRacingCatalog4229938(configDir string) ([]any, error) { RacingCatalog4229938_cacheLock.RLock() if RacingCatalog4229938_cached { defer RacingCatalog4229938_cacheLock.RUnlock() return RacingCatalog4229938_entries, nil } RacingCatalog4229938_cacheLock.RUnlock() RacingCatalog4229938_cacheLock.Lock() defer RacingCatalog4229938_cacheLock.Unlock() if RacingCatalog4229938_cached { return RacingCatalog4229938_entries, nil } filePath := filepath.Join(configDir, "RacingCatalog.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) } } RacingCatalog4229938_entries = result RacingCatalog4229938_cached = true return result, nil } func RacingCatalog4229938_Records(root string, fileName string) []any { // Catalog helper RacingCatalog4229938_Records return nil } // ⛑️ TryGetUInt32 遇到非 Number 会**抛**(不是返回 false)—— 先判 ValueKind。 // 同 ExtractionShooterCatalog4229938 的 U32/I32/Bool(硬规则 195)。 func RacingCatalog4229938_U32(source any, name string) uint32 { // Catalog helper RacingCatalog4229938_U32 return 0 } func RacingCatalog4229938_UIntList(source any, name string) []uint32 { // Catalog helper RacingCatalog4229938_UIntList return nil }