90 lines
2.6 KiB
Go
90 lines
2.6 KiB
Go
package common
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
type ComicDessertCycle struct {
|
|
ID uint32
|
|
ProgressAmount uint32
|
|
LevelIDList []uint32
|
|
}
|
|
|
|
type ComicDessertLevel struct {
|
|
ID uint32
|
|
LevelConfigPath string
|
|
RequiredCoin uint32
|
|
}
|
|
|
|
type ComicDessertCatalog struct {
|
|
Cycles []ComicDessertCycle
|
|
Levels []ComicDessertLevel
|
|
}
|
|
|
|
// Read the two captured flat tables. Never initialize gameplay by inventing a
|
|
// cycle/level ID, and never write user progress from this catalog reader.
|
|
func LoadComicDessertCatalog() (*ComicDessertCatalog, error) {
|
|
raw, err := ReadResourceFile("resources/ComicDessertCatalog.json")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var resource struct {
|
|
Format uint32 `json:"format_version"`
|
|
Assembly string `json:"client_assembly_sha256"`
|
|
Evidence string `json:"evidence_id"`
|
|
ComicDessertCatalog
|
|
}
|
|
if err = json.Unmarshal(raw, &resource); err != nil {
|
|
return nil, err
|
|
}
|
|
digest, err := hex.DecodeString(resource.Assembly)
|
|
if err != nil || len(digest) != 32 || resource.Format != 1 || resource.Evidence == "" {
|
|
return nil, fmt.Errorf("ComicDessert catalog provenance invalid")
|
|
}
|
|
raw, err = ReadResourceFile("resources/PreviewGameplayCatalog.json")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var client struct {
|
|
Assembly string `json:"client_assembly_sha256"`
|
|
}
|
|
if err = json.Unmarshal(raw, &client); err != nil || client.Assembly != resource.Assembly {
|
|
return nil, fmt.Errorf("ComicDessert/client catalog identity mismatch")
|
|
}
|
|
levels := make(map[uint32]bool, len(resource.Levels))
|
|
for _, level := range resource.Levels {
|
|
if level.ID == 0 || level.LevelConfigPath == "" || levels[level.ID] {
|
|
return nil, fmt.Errorf("invalid ComicDessert level catalog")
|
|
}
|
|
levels[level.ID] = true
|
|
}
|
|
cycles := make(map[uint32]bool, len(resource.Cycles))
|
|
for _, cycle := range resource.Cycles {
|
|
if cycle.ID == 0 || cycles[cycle.ID] || len(cycle.LevelIDList) == 0 {
|
|
return nil, fmt.Errorf("invalid ComicDessert cycle catalog")
|
|
}
|
|
cycles[cycle.ID] = true
|
|
for _, id := range cycle.LevelIDList {
|
|
if !levels[id] {
|
|
return nil, fmt.Errorf("ComicDessert cycle references absent level %d", id)
|
|
}
|
|
}
|
|
}
|
|
if len(cycles) == 0 || len(levels) == 0 {
|
|
return nil, fmt.Errorf("ComicDessert catalog is empty")
|
|
}
|
|
return &resource.ComicDessertCatalog, nil
|
|
}
|
|
|
|
func (c *ComicDessertCatalog) InitialCycle() ComicDessertCycle {
|
|
var first ComicDessertCycle
|
|
for _, cycle := range c.Cycles {
|
|
if first.ID == 0 || cycle.ProgressAmount < first.ProgressAmount || (cycle.ProgressAmount == first.ProgressAmount && cycle.ID < first.ID) {
|
|
first = cycle
|
|
}
|
|
}
|
|
return first
|
|
}
|