108 lines
3.6 KiB
Go
108 lines
3.6 KiB
Go
package catalogs
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
)
|
|
|
|
var _ = json.RawMessage{}
|
|
var _ = sync.Mutex{}
|
|
var _ = os.ReadFile
|
|
var _ = filepath.Join
|
|
|
|
//
|
|
// One achievement row, projected from AchievementConfig.json by _gen_ach_cfg.py.
|
|
// FirstCategoryType / SecCategoryType mirror the table's
|
|
// FirstCategoryType / SecCategoryType columns, which is how NewAchievementMgr buckets the ids
|
|
// into tabs during its ctor (it reads the client's own AchievementConfig, so we only need the ids
|
|
// and their completion state to line up).
|
|
//
|
|
type AchievementEntry4229938 struct {
|
|
Id uint32 `json:"id"`
|
|
Quality uint32 `json:"quality"`
|
|
Hide bool `json:"hide"`
|
|
FirstCategoryType uint32 `json:"firstCategoryType"`
|
|
SecCategoryType uint32 `json:"secCategoryType"`
|
|
MaxProgressBarNum uint32 `json:"maxProgressBarNum"`
|
|
}
|
|
|
|
//
|
|
// Build-4229938 achievement catalog. The source table is AchievementConfig.json, which does not
|
|
// ship in the v0.3 Configs folder; it comes from 补丁和工具\ConfigDump.zip. Regenerate with
|
|
// _gen_ach_cfg.py.
|
|
// Achievements travel in the login payload, and the client does read them:
|
|
// lua/LX6/Data/Player/PlayerData/PlayerInfoAchievementData.lua:21
|
|
// t.AchievementInfos = info.InfoAchievement.AchievementInfos
|
|
// lua/LX6/Manager/GameSystem/NewAchievementMgr.lua:45,99,115
|
|
// for k, v in pairs(gPlayerManager.infoAchievement.bindData.AchievementInfos) do
|
|
// self:OnAchievementFinished(k, v)
|
|
// The panel opens only when SystemUnlockConfig id 119 ("成就") is unlocked; the login payload is
|
|
// already granted every authored SystemUnlockConfig row, so nothing extra is needed here.
|
|
//
|
|
const (
|
|
// UX.Game.AchievementStatus.None (dump TypeDefIndex 33405).
|
|
AchievementCatalog4229938_StatusNone byte = 0
|
|
// UX.Game.AchievementStatus.Completed.
|
|
AchievementCatalog4229938_StatusCompleted byte = 1
|
|
// UX.Game.AchievementStatus.Rewarded.
|
|
AchievementCatalog4229938_StatusRewarded byte = 2
|
|
//
|
|
// Completed | Rewarded — the state a fully settled achievement ends up in. The Lua enum names
|
|
// are obfuscated in the decompile, so only the dump values are trustworthy.
|
|
//
|
|
AchievementCatalog4229938_StatusSettled byte = AchievementCatalog4229938_StatusCompleted | AchievementCatalog4229938_StatusRewarded
|
|
)
|
|
|
|
var (
|
|
AchievementCatalog4229938_cacheLock sync.RWMutex
|
|
AchievementCatalog4229938_cached = false
|
|
AchievementCatalog4229938_entries []any
|
|
)
|
|
|
|
// LoadAchievementCatalog4229938 loads catalog records from client config directory
|
|
func LoadAchievementCatalog4229938(configDir string) ([]any, error) {
|
|
AchievementCatalog4229938_cacheLock.RLock()
|
|
if AchievementCatalog4229938_cached {
|
|
defer AchievementCatalog4229938_cacheLock.RUnlock()
|
|
return AchievementCatalog4229938_entries, nil
|
|
}
|
|
AchievementCatalog4229938_cacheLock.RUnlock()
|
|
|
|
AchievementCatalog4229938_cacheLock.Lock()
|
|
defer AchievementCatalog4229938_cacheLock.Unlock()
|
|
if AchievementCatalog4229938_cached { return AchievementCatalog4229938_entries, nil }
|
|
|
|
filePath := filepath.Join(configDir, "AchievementCatalog.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)
|
|
}
|
|
}
|
|
|
|
AchievementCatalog4229938_entries = result
|
|
AchievementCatalog4229938_cached = true
|
|
return result, nil
|
|
}
|
|
|
|
func AchievementCatalog4229938_UInt(row any, name string) uint32 {
|
|
// Catalog helper AchievementCatalog4229938_UInt
|
|
return 0
|
|
}
|
|
|