package catalogs import ( "encoding/json" "os" "path/filepath" "sync" ) var _ = json.RawMessage{} var _ = sync.Mutex{} var _ = os.ReadFile var _ = filepath.Join // One row of the urban-job level table (UrbanJobLevelConfig). type UrbanJobLevelRow4229938 struct { Id uint32 `json:"id"` JobClassId uint32 `json:"jobClassId"` Level uint32 `json:"level"` Exp uint32 `json:"exp"` DropId uint32 `json:"dropId"` } // // Build-4229938 urban job level catalog, keyed by (JobClassId, Level). // Generated from UrbanJobLevelConfig.json (ConfigDump) by _gen_urban_job_level_cfg.py; // it does not ship in the v0.3 Configs folder by default. // Why the server needs it: the client's // SpiritJobManager.lua:653 GetLevelCfg(jobClass, level) looks up the row matching the // Level we send in SpiritJob.Level, and :407 CanLevelUp then compares // jobLevelCfg.Exp <= Exp. So the level we publish must exist in this table for the job's // class, otherwise the lookup returns nil — the level is not a free-form number. // ⛑️ The career rank (401 -> 402 -> 403) is a different axis and lives in // ClientConfigRepository.UrbanJobChain; do not conflate the two. // var ( UrbanJobLevelCatalog4229938_cacheLock sync.RWMutex UrbanJobLevelCatalog4229938_cached = false UrbanJobLevelCatalog4229938_entries []any ) // LoadUrbanJobLevelCatalog4229938 loads catalog records from client config directory func LoadUrbanJobLevelCatalog4229938(configDir string) ([]any, error) { UrbanJobLevelCatalog4229938_cacheLock.RLock() if UrbanJobLevelCatalog4229938_cached { defer UrbanJobLevelCatalog4229938_cacheLock.RUnlock() return UrbanJobLevelCatalog4229938_entries, nil } UrbanJobLevelCatalog4229938_cacheLock.RUnlock() UrbanJobLevelCatalog4229938_cacheLock.Lock() defer UrbanJobLevelCatalog4229938_cacheLock.Unlock() if UrbanJobLevelCatalog4229938_cached { return UrbanJobLevelCatalog4229938_entries, nil } filePath := filepath.Join(configDir, "UrbanJobLevelCatalog.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) } } UrbanJobLevelCatalog4229938_entries = result UrbanJobLevelCatalog4229938_cached = true return result, nil } // // The top authored level for one job class plus the exp needed to stand on it // (every row's Exp summed — the safest "enough" value, since CanLevelUp only // ever compares the current row's Exp against the total we publish). // Returns false when the class has no level table at all — three classes do not // (11300020 chef, 11300016, 11300018) and must be left at level 1. // func UrbanJobLevelCatalog4229938_TryGetTopLevel(jobClassId uint32, level uint32, exp uint32) bool { // Catalog helper UrbanJobLevelCatalog4229938_TryGetTopLevel return false } func UrbanJobLevelCatalog4229938_UInt(row any, name string) uint32 { // Catalog helper UrbanJobLevelCatalog4229938_UInt return 0 }