package common import ( "crypto/sha256" "encoding/hex" "encoding/json" "fmt" ) type CurrencyWarsSpotlight struct { ID uint32 `json:"ID"` SuitableRoles []uint32 `json:"SuitableAvatarList"` IsCarry bool `json:"IsCarry"` IsOCEffective bool `json:"IsOCEffective"` EnemyDiffLvAdd int32 `json:"EnemyDiffLvAdd"` TraitID uint32 `json:"TraitID"` JsonPath string `json:"JsonPath"` EffectParams []string `json:"EffectParamList"` } type CurrencyWarsSpotlightPolicy struct { Format uint32 `json:"format_version"` Client string `json:"target_client_version"` Assembly string `json:"target_assembly_sha256"` OfferCount uint32 `json:"offer_count"` FreeRefreshCount uint32 `json:"free_refresh_count"` } func (c *CurrencyWarsCatalog) SpotlightData() (map[uint32]CurrencyWarsSpotlight, CurrencyWarsSpotlightPolicy, error) { var policy CurrencyWarsSpotlightPolicy var resource struct { Format uint32 `json:"format_version"` Client string `json:"target_client_version"` Assembly string `json:"target_assembly_sha256"` Capture string `json:"source_capture_sha256"` Entries []CurrencyWarsSpotlight `json:"entries"` } raw, e := ReadResourceFile("resources/CurrencyWarsSpotlights.json") if e != nil { return nil, policy, e } if e = json.Unmarshal(raw, &resource); e != nil { return nil, policy, e } digest, e := hex.DecodeString(resource.Capture) if e != nil || len(digest) != sha256.Size || resource.Format != 1 || resource.Client != c.ClientVersion || resource.Assembly != c.Provenance.GameAssemblySHA256 || len(resource.Entries) == 0 { return nil, policy, fmt.Errorf("CW Spotlight capture revision differs") } rows := make(map[uint32]CurrencyWarsSpotlight, len(resource.Entries)) for _, r := range resource.Entries { // Native rows can have an empty JsonPath; some effects are resolved by // their own engine rather than an external level graph. Retain that // distinction instead of rejecting the entire valid handbook capture. if _, exists := rows[r.ID]; exists || r.ID == 0 { return nil, policy, fmt.Errorf("CW Spotlight configuration identity invalid: %d", r.ID) } for _, v := range r.EffectParams { if !currencyWarsDecimal.MatchString(v) { return nil, policy, fmt.Errorf("CW Spotlight effect parameter invalid") } } rows[r.ID] = r } raw, e = ReadResourceFile("resources/CurrencyWarsSpotlightPolicy.json") if e != nil { return nil, policy, e } if e = json.Unmarshal(raw, &policy); e != nil { return nil, policy, e } if policy.Format != 1 || policy.Client != c.ClientVersion || policy.Assembly != c.Provenance.GameAssemblySHA256 || policy.OfferCount == 0 || policy.OfferCount > uint32(len(rows)) { return nil, policy, fmt.Errorf("CW Spotlight selection policy invalid") } return rows, policy, nil }