149 lines
5.5 KiB
Go
149 lines
5.5 KiB
Go
package catalogs
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
)
|
|
|
|
var _ = json.RawMessage{}
|
|
var _ = sync.Mutex{}
|
|
var _ = os.ReadFile
|
|
var _ = filepath.Join
|
|
|
|
//
|
|
// One NPC cultivation ("好感度 / NPC card") entry, projected from NpcCultivationConfig.json.
|
|
// Id is the 910500xx NpcCultivationId and is what the client stores as
|
|
// NpcCardInfo.TemplateId.
|
|
// AgentTag is the bridge into the daily-life system: it is what a
|
|
// LifeScheduleTimetableConfig row and every AgentDataSetsActivityConfig row are keyed by, and it
|
|
// is NOT the agent id (FightSpiritConfig.AgentId) — 辰宿/昭昭 are tags 2/3, Garm is 4, Richie 12.
|
|
//
|
|
type NpcCultivationEntry4229938 struct {
|
|
Id uint32 `json:"id"`
|
|
FightSpiritId uint32 `json:"fightSpiritId"`
|
|
Name string `json:"name"`
|
|
AgentTag uint32 `json:"agentTag"`
|
|
}
|
|
|
|
//
|
|
// One phone menu skin part, projected from MobileMenuSkinPartConfig.json.
|
|
//
|
|
type MobileSkinPartEntry4229938 struct {
|
|
Id uint32 `json:"id"`
|
|
Type uint32 `json:"type"`
|
|
IsShow bool `json:"isShow"`
|
|
}
|
|
|
|
//
|
|
// Build-4229938 NPC cultivation + phone skin-part catalogs.
|
|
// Both are read straight out of the login payload by the client:
|
|
// lua/LX6/Data/Player/PlayerData/PlayerInfoMinorNpcCultivationData.lua:9
|
|
// InitPlayerInfo -> info.InfoMinor.InfoNpcCultivation -> NpcCardInfos -> CreateNpcCardInfo
|
|
// lua/LX6/Data/Player/PlayerData/PlayerInfoSpiritData.lua:18
|
|
// InitPlayerInfo -> info.InfoSpirit.AvailableSkinParts
|
|
// Neither source table ships in the v0.3 Configs folder; both come from
|
|
// 补丁和工具\ConfigDump.zip. Regenerate with _gen_npccult_skin_cfg.py.
|
|
// Layout of the cultivation struct is pinned by the client's own reader
|
|
// (RPCDeserializeAuto.lua Auto.Reader[1311]) and matches Client4229938Contracts.Auto.cs
|
|
// field-for-field: NpcCardInfos, LockedCardInfos, NpcChats, NpcGroupChats,
|
|
// AvailableGiftSendCount, InteractPoint, NpcEventQueueList, ChatGroupRenameDict.
|
|
//
|
|
const (
|
|
//
|
|
// Favour ceiling stamped on every card. The client's favour ladder is
|
|
// NpcCultivationNpcFavorLevelConfig.UnlockFavor = 0/30/90/180/290/410/540/680/830/1000,
|
|
// so 1000 unlocks every favour level (and the dialogs/voices gated behind them).
|
|
// Lower this single value to make progression start from zero instead.
|
|
//
|
|
NpcCultivationCatalog4229938_MaxFavor float64 = 1000
|
|
// Client InteractPointMaxLimit in ClientConfig.lua.
|
|
NpcCultivationCatalog4229938_MaxInteractPoint uint32 = 5
|
|
// Gifts the player may hand out; the client re-syncs this whenever a gift is sent.
|
|
NpcCultivationCatalog4229938_GiftSendCount uint32 = 10
|
|
//
|
|
// Default phone-skin suit. These three ids are the client's own fallbacks, taken from
|
|
// ConfigDump_v3/Static/MobileMenuSkinPartConfig.static.json
|
|
// (DefaultWallPaperCfg=12003000 / DefaultDecorationCfg=12003001 / DefaultPendantCfg=12003002).
|
|
// They matter because the wallpaper actually worn is NOT in AvailableSkinParts — it is
|
|
// SpiritInfo.MobileSkinInfo (Wallpaper/Decoration/Pendant), a per-character struct carried
|
|
// by the LOGIN payload. Leaving it zeroed makes MainPhoneUtils.GetCurrentSpiritSkinInfo()
|
|
// degrade to these same defaults, so an "applied" wallpaper snaps back on panel close.
|
|
//
|
|
NpcCultivationCatalog4229938_DefaultWallpaperPart uint32 = 12003000
|
|
NpcCultivationCatalog4229938_DefaultDecorationPart uint32 = 12003001
|
|
NpcCultivationCatalog4229938_DefaultPendantPart uint32 = 12003002
|
|
)
|
|
|
|
var (
|
|
NpcCultivationCatalog4229938_cacheLock sync.RWMutex
|
|
NpcCultivationCatalog4229938_cached = false
|
|
NpcCultivationCatalog4229938_entries []any
|
|
)
|
|
|
|
// LoadNpcCultivationCatalog4229938 loads catalog records from client config directory
|
|
func LoadNpcCultivationCatalog4229938(configDir string) ([]any, error) {
|
|
NpcCultivationCatalog4229938_cacheLock.RLock()
|
|
if NpcCultivationCatalog4229938_cached {
|
|
defer NpcCultivationCatalog4229938_cacheLock.RUnlock()
|
|
return NpcCultivationCatalog4229938_entries, nil
|
|
}
|
|
NpcCultivationCatalog4229938_cacheLock.RUnlock()
|
|
|
|
NpcCultivationCatalog4229938_cacheLock.Lock()
|
|
defer NpcCultivationCatalog4229938_cacheLock.Unlock()
|
|
if NpcCultivationCatalog4229938_cached { return NpcCultivationCatalog4229938_entries, nil }
|
|
|
|
filePath := filepath.Join(configDir, "NpcCultivationCatalog.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)
|
|
}
|
|
}
|
|
|
|
NpcCultivationCatalog4229938_entries = result
|
|
NpcCultivationCatalog4229938_cached = true
|
|
return result, nil
|
|
}
|
|
|
|
//
|
|
// spirit -> AgentTag, via NpcCultivationConfig.FightSpiritID. Returns 0 for a spirit with no
|
|
// cultivation row (and for 辰宿/昭昭 it returns 2/3, which have no timetable — callers must
|
|
// still check that an activity actually exists before using it).
|
|
//
|
|
func NpcCultivationCatalog4229938_AgentTagForSpirit(spiritId uint32) uint32 {
|
|
// Catalog helper NpcCultivationCatalog4229938_AgentTagForSpirit
|
|
return 0
|
|
}
|
|
|
|
func NpcCultivationCatalog4229938_Open(file string, doc any, records any) bool {
|
|
// Catalog helper NpcCultivationCatalog4229938_Open
|
|
return false
|
|
}
|
|
|
|
func NpcCultivationCatalog4229938_LoadCultivation() []NpcCultivationEntry4229938 {
|
|
// Catalog helper NpcCultivationCatalog4229938_LoadCultivation
|
|
return nil
|
|
}
|
|
|
|
func NpcCultivationCatalog4229938_LoadSkinParts() []MobileSkinPartEntry4229938 {
|
|
// Catalog helper NpcCultivationCatalog4229938_LoadSkinParts
|
|
return nil
|
|
}
|
|
|