Files
AIGame/AIClient/AgentScripts/VerifyProgression.cs
T

56 lines
3.9 KiB
C#

using System;
using System.IO;
using System.Linq;
using HotUpdate.Gameplay;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
public static class VerifyProgression
{
static void Check(bool pass,string message) { if (!pass) throw new Exception(message); }
public static string Domain()
{
string repo=Directory.GetParent(Application.dataPath).Parent.FullName;
var config=JsonUtility.FromJson<PrototypeConfig>(File.ReadAllText(Path.Combine(repo,"Config/Gameplay/greenfield.json")));
Check(PrototypeConfig.Valid(config),"Invalid canonical config");
Check(config.pets.Length==10&&config.stages.Length==20,"Expected ten partners and twenty stages");
Check(config.capture.weights.Length==10&&config.rewards.chests[1].choices.Length==10,"Capture pool or chest choices not widened");
foreach(var stage in config.stages) Check(!string.IsNullOrEmpty(stage.chapter),"Stage missing chapter");
var vectors=(JArray)JObject.Parse(File.ReadAllText(Path.Combine(repo,"Tools/output/progression_parity.json")))["entries"];
Check(vectors.Count>=50,"Missing C++ parity vectors");
int wins=0,losses=0;
foreach(var v in vectors)
{
var s=JsonUtility.FromJson<BattleSnapshot>(v["snapshot"].ToString());
var result=JsonUtility.FromJson<PrototypeResult>(v["result"].ToString());
// Replay snapshots are presentation-only saves; give them a schema matching their roster width.
int replaySchema=s.stages.Length>=10?9:s.stages.Length==5?3:1;
var save=new PrototypeSave { schema=replaySchema,level=s.level,stages=s.stages,shards=new int[s.stages.Length],formation=s.formation };
if(replaySchema>=2){save.selectedStage=1;save.clearedStages=new int[replaySchema>=9?20:5];save.clearedStages[0]=1;}
if(replaySchema>=4){save.campLayout=new[]{-1,-1,-1};save.decorations=new int[3];save.restPet=0;}
if(replaySchema>=5){save.dailyDay=1;save.signinDays=1;save.dailyProgress=new int[3];save.dailyClaimed=new int[3];save.signinClaimed=new int[7];}
if(replaySchema>=6)save.shopBought=new int[3];
if(replaySchema>=7)save.mails=new PrototypeMail[0];
if(replaySchema>=8){save.chests=new int[3];save.chestDailyClaimed=0;}
var game=new PrototypeGame(save);
var battle=new PrototypeBattle("parity",game,s.legacy?null:s.config,s.legacy?1:s.stageId);
for(int tick=0;tick<2500&&!battle.Finished;tick++) battle.Tick();
Check(battle.Finished && battle.Won==result.won && battle.Durability==result.durability && battle.Defeated==result.defeated && Mathf.Abs(battle.Time-result.duration)<.002f,
"C#/C++ drift at stage "+s.stageId+" level "+s.level+" party "+string.Join(",",s.formation)+"; Unity="+battle.Won+"/"+battle.Time+" server="+result.won+"/"+result.duration);
if(battle.Won) wins++;else losses++;
}
Check(wins>0&&losses>0,"Parity must cover wins and losses");
foreach(string screen in new[]{"Stages","Pinball","Capture","Pets","Formation","Battle","Camp","Build","Tasks","Signin","Bag","Shop","Mail","Chest","Settings"})
{
var prefab=AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Bundles/UI/Prefab/UI_Prototype"+screen+".prefab");
Check(prefab!=null,"Missing "+screen);
Check(prefab.GetComponentsInChildren<TextMeshProUGUI>(true).All(t=>t.font!=null),"Missing TMP font "+screen);
foreach(var image in prefab.GetComponentsInChildren<Image>(true).Where(i=>i.type==Image.Type.Sliced)) Check(image.sprite!=null&&image.sprite.border.x>0&&image.sprite.border.y>0,"Invalid nine-slice "+screen);
}
return "PASS: "+vectors.Count+" C++/Unity parity cases including "+wins+" wins / "+losses+" losses and pending migration; sixteen authored UI prefabs, fonts, nine-slices.";
}
}