package common import ( "crypto/sha256" "encoding/hex" "encoding/json" "fmt" ) type CurrencyWarsMonsterRow struct { ID uint32 `json:"MonsterID"` Tier uint32 `json:"MonsterTier"` Star1 uint32 `json:"Star1EliteGroup3"` Star2 uint32 `json:"Star2EliteGroup3"` Star3 uint32 `json:"Star3EliteGroup3"` Star4 uint32 `json:"Star4EliteGroup3"` } // This is deliberately partial coverage: callers reject an absent native row. func LoadCurrencyWarsMonsters(c *CurrencyWarsCatalog) (map[uint32]CurrencyWarsMonsterRow, error) { raw, err := ReadResourceFile("resources/CurrencyWarsMonsters.json") if err != nil { return nil, err } var r struct { Format uint32 `json:"format_version"` Client string `json:"target_client_version"` Assembly string `json:"target_assembly_sha256"` Capture string `json:"source_capture_sha256"` Policy string `json:"encounter_camp_policy"` Entries []CurrencyWarsMonsterRow `json:"entries"` } if err = json.Unmarshal(raw, &r); err != nil { return nil, err } if c == nil || r.Format != 1 || r.Client != c.ClientVersion || r.Assembly != c.Provenance.GameAssemblySHA256 { return nil, fmt.Errorf("CW monster revision differs") } digest, err := hex.DecodeString(r.Capture) if err != nil || len(digest) != sha256.Size || r.Policy != "uniform_compatible_active_camp_same_tier" { return nil, fmt.Errorf("CW monster provenance/policy missing") } rows := map[uint32]CurrencyWarsMonsterRow{} for _, v := range r.Entries { if _, dup := rows[v.ID]; dup || v.ID == 0 || v.Star1 == 0 || v.Star2 == 0 || v.Star3 == 0 || v.Star4 == 0 { return nil, fmt.Errorf("CW monster identity/star group invalid") } rows[v.ID] = v } if len(rows) == 0 { return nil, fmt.Errorf("CW monster capture empty") } return rows, nil }