99 lines
11 KiB
C#
99 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using HotUpdate.Gameplay;
|
|
using HotUpdate.Net;
|
|
using HotUpdate.UI;
|
|
using TMPro;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.EventSystems;
|
|
|
|
public static class VerifyDaily
|
|
{
|
|
static PrototypeFlow Flow=>UnityEngine.Object.FindObjectOfType<PrototypeFlow>();
|
|
static void Check(bool b,string message){if(!b)throw new Exception(message);}
|
|
static T Get<T>(string name)=>(T)typeof(PrototypeFlow).GetField(name,BindingFlags.NonPublic|BindingFlags.Instance).GetValue(Flow);
|
|
static void Set(string name,object value)=>typeof(PrototypeFlow).GetField(name,BindingFlags.NonPublic|BindingFlags.Instance).SetValue(Flow,value);
|
|
static async Task Until(Func<bool> condition,int seconds=20){var end=DateTime.UtcNow.AddSeconds(seconds);while(!condition()){Check(DateTime.UtcNow<end,"Daily timed out: "+Flow?.Page);await Task.Delay(100);}}
|
|
static Button Button(string name)=>UnityEngine.Object.FindObjectsOfType<Button>().Single(b=>b.name=="Btn_"+name&&b.gameObject.activeInHierarchy);
|
|
static void Click(string name)
|
|
{
|
|
var b=Button(name);Check(b.interactable,"Disabled "+name);Canvas.ForceUpdateCanvases();var rect=b.GetComponent<RectTransform>();
|
|
var pointer=new PointerEventData(EventSystem.current){position=RectTransformUtility.WorldToScreenPoint(null,rect.TransformPoint(rect.rect.center)),button=PointerEventData.InputButton.Left};
|
|
var hits=new List<RaycastResult>();EventSystem.current.RaycastAll(pointer,hits);Check(hits.Count>0&&ExecuteEvents.GetEventHandler<IPointerClickHandler>(hits[0].gameObject)==b.gameObject,"Click blocked "+name);ExecuteEvents.Execute(b.gameObject,pointer,ExecuteEvents.pointerClickHandler);
|
|
}
|
|
static bool Dot(string name)=>Get<MainHudView>("_hud").GetComponentsInChildren<Transform>(true).Single(t=>t.name==name).gameObject.activeSelf;
|
|
static async Task Capture(string name)
|
|
{
|
|
await Task.Delay(150);var type=AppDomain.CurrentDomain.GetAssemblies().Select(a=>a.GetType("Unity.Pipeline.Editor.Commands.Capture.CaptureCommands")).First(t=>t!=null);
|
|
type.GetMethod("CaptureGameView",BindingFlags.Static|BindingFlags.Public).Invoke(null,new object[]{1080,1920,null,"Screenshots/daily_"+name+".png",false,0,"screen"});
|
|
}
|
|
static async Task Shot(){int count=Flow.Game.State.shots;Click("Fire");await Until(()=>!Flow.IsBusy&&Flow.Game.State.shots==count+1);}
|
|
static async Task SyncHome(){Flow.Handle("Home");Set("_needsSync",true);Flow.Handle("Home");await Until(()=>!Flow.IsBusy);await Task.Delay(150);}
|
|
public static async Task<string> Start()
|
|
{
|
|
await Until(()=>Flow?.Game!=null&&!Flow.IsBusy);SessionState.SetString("AIGame.G1.original",JsonUtility.ToJson(Flow.Game.State));SessionState.SetString("AIGame.G1.originalEndpoint",Get<string>("_httpBase"));
|
|
AuthResponse account=null;string error=null;bool done=false;string user="g1live_daily_"+Guid.NewGuid().ToString("N");
|
|
Flow.StartCoroutine(AuthApi.Register("http://127.0.0.1:18081",user,"isolated-g1-test-password",(r,e)=>{account=r;error=e;done=true;}));await Until(()=>done);Check(account!=null,"Register failed "+error);
|
|
File.WriteAllText(Path.Combine(Application.dataPath,"../../Tools/output/g1-live/account.txt"),user);var session=new SessionData{Pid=account.pid,Token=account.token,Username=user};
|
|
Set("_session",new Func<SessionData>(()=>session));Set("_profile",new Func<long>(()=>session.Pid));Set("_httpBase","http://127.0.0.1:18081");Set("_boundProfile",0L);Flow.Handle("Home");await Until(()=>!Flow.IsBusy);await Task.Delay(150);
|
|
Check(Flow.Game.State.schema>=5&&Flow.Game.State.signinDays==1&&Dot("Dot_Daily")&&!Dot("Dot_Tasks"),"Fresh daily/sign-in state or red dots wrong");await Capture("home");
|
|
Click("Daily");await Until(()=>Flow.Page=="UI_PrototypeSignin");Check(Button("Signin0").interactable&&!Button("Signin1").interactable,"Sign-in locks wrong");await Capture("signin1");
|
|
int balls=Flow.Game.State.balls;Click("Signin0");await Until(()=>!Flow.IsBusy&&Flow.Game.State.signinClaimed[0]==1);Check(Flow.Game.State.balls==balls+10&&!Dot("Dot_Daily"),"Day1 reward or red dot wrong");await Capture("signin_reward");Click("Ok");
|
|
Set("_needsSync",true);Flow.Handle("Home");await Until(()=>!Flow.IsBusy);Check(Flow.Game.State.signinDays==1&&!Button("Signin0").interactable,"Same-day reconnect advances sign-in");
|
|
Click("ToTasks");await Until(()=>Flow.Page=="UI_PrototypeTasks");Check(!Button("ClaimDaily0").interactable&&!Button("ClaimGoal").interactable,"Incomplete task claimable");await Capture("tasks_empty");
|
|
Click("GoDaily0");await Until(()=>Flow.Page=="UI_PrototypePinball");await Shot();await Shot();await Shot();Check(Flow.Game.State.dailyProgress[0]==3&&Dot("Dot_Tasks"),"Real shot events not counted");
|
|
Click("Back");await Task.Delay(150);Click("Tasks");await Until(()=>Flow.Page=="UI_PrototypeTasks");await Capture("shot_ready");balls=Flow.Game.State.balls;
|
|
Click("ClaimDaily0");await Until(()=>!Flow.IsBusy&&Flow.Game.State.dailyClaimed[0]==1);Check(Flow.Game.State.balls==balls+5&&!Dot("Dot_Tasks"),"Shot claim repeated or dot retained");Click("Ok");
|
|
SessionState.SetInt("Daily.coins",Flow.Game.State.coins);SessionState.SetInt("Daily.candy",Flow.Game.State.candy);SessionState.SetInt("Daily.balls",Flow.Game.State.balls);
|
|
Click("GoDaily1");await Until(()=>Flow.Page=="UI_PrototypeStages");Click("Stage1");await Until(()=>Flow.Page=="UI_PrototypeFormation");Click("StartBattle");await Until(()=>Flow.Page=="UI_PrototypeBattle");Click("Speed");await Until(()=>Flow.Battle.Time>=12);
|
|
return "PASS live first login +10 once, locked future days, same-day reconnect stable, three real shots, daily +5 once and reward dots; tutorial battle running.";
|
|
}
|
|
public static async Task<string> Finish()
|
|
{
|
|
if(Flow.Battle==null||!Flow.Battle.Finished||Flow.IsBusy)return "RUNNING time="+Flow?.Battle?.Time;
|
|
Check(Flow.Battle.Won&&Flow.Game.State.dailyProgress[1]==1&&Flow.Game.State.balls==SessionState.GetInt("Daily.balls",0)+3&&Flow.Game.State.coins==SessionState.GetInt("Daily.coins",0)+80&&Flow.Game.State.candy==SessionState.GetInt("Daily.candy",0)+40,"Battle/task settlement mismatch");
|
|
Click("Home");await Task.Delay(150);Click("Tasks");await Until(()=>Flow.Page=="UI_PrototypeTasks");await Capture("battle_ready");
|
|
int balls=Flow.Game.State.balls;Click("ClaimGoal");await Until(()=>!Flow.IsBusy&&Flow.Game.State.goalClaimed);Check(Flow.Game.State.balls==balls+5,"Teaching goal wrong");Click("Ok");
|
|
Click("ClaimDaily1");await Until(()=>!Flow.IsBusy&&Flow.Game.State.dailyClaimed[1]==1);Check(Flow.Game.State.balls==balls+10,"Daily battle claim wrong");Click("Ok");
|
|
return "PASS live normally finished battle counted, exact first-clear reward, teaching +5 and daily battle +5 separately once.";
|
|
}
|
|
public static async Task<string> RestAndClaim()
|
|
{
|
|
await SyncHome();Click("NavHome");await Until(()=>Flow.Page=="UI_PrototypeCamp");int balls=Flow.Game.State.balls;Click("RestPet0");Click("Interact");await Until(()=>!Flow.IsBusy&&Flow.Game.State.dailyProgress[2]==1);
|
|
Check(Flow.Game.State.balls==balls,"Interaction directly gave resource");Click("Back");await Task.Delay(150);Click("Tasks");await Until(()=>Flow.Page=="UI_PrototypeTasks");await Capture("rest_ready");
|
|
Click("ClaimDaily2");await Until(()=>!Flow.IsBusy&&Flow.Game.State.dailyClaimed[2]==1);Check(Flow.Game.State.balls==balls+5&&!Dot("Dot_Tasks"),"Interaction task award or red dot wrong");Click("Ok");await Capture("tasks_claimed");
|
|
return "PASS actual rest interaction has no direct reward; third daily task gives +5 once; all three claimed and task red dot cleared.";
|
|
}
|
|
public static async Task<string> EarnedSignin()
|
|
{
|
|
await SyncHome();Check(Flow.Game.State.signinDays==3&&Dot("Dot_Daily"),"Earned sign-in fixture missing");Click("Daily");await Until(()=>Flow.Page=="UI_PrototypeSignin");
|
|
Check(Button("Signin1").interactable&&Button("Signin2").interactable&&!Button("Signin3").interactable,"Earned sign-in lock/preservation wrong");await Capture("signin3");
|
|
var api=Get<PrototypeApi>("_api");var command=api.Command("signin.claim",Flow.Game.State.revision,item:1);int balls=Flow.Game.State.balls;PrototypeReply response=null;string error=null;
|
|
Flow.StartCoroutine(api.Send(command,(r,e)=>{response=r;error=e;}));await Until(()=>response!=null||error!=null);Check(response?.ok==true,"Sign-in before simulated lost ack failed");
|
|
var session=Get<Func<SessionData>>("_session")();string key="AIGame.G1.pending."+Uri.EscapeDataString("http://127.0.0.1:18081")+"."+session.Pid;
|
|
PlayerPrefs.SetString(key,JsonUtility.ToJson(command));PlayerPrefs.Save();Set("_needsSync",true);Flow.Handle("Home");await Until(()=>!Flow.IsBusy&&Get<PrototypeReply>("_reply").replayed);
|
|
Check(Flow.Game.State.balls==balls+5&&Flow.Game.State.signinClaimed[1]==1&&!api.HasPending,"Sign-in retry granted twice");
|
|
var dialog=UiManager.Instance.Get(ConfirmDialogView.PrefabName).GetComponent<ConfirmDialogView>().CaptureState();Check(dialog.Visible&&dialog.Title=="奖励已领取","Original sign-in receipt not shown");await Capture("recovery");Click("Ok");
|
|
Click("Signin2");await Until(()=>!Flow.IsBusy&&Flow.Game.State.signinClaimed[2]==1);Check(Flow.Game.State.balls==balls+10&&!Dot("Dot_Daily"),"Earned reward preservation or red dot wrong");Click("Ok");
|
|
Set("_boundProfile",0L);Flow.Handle("Home");await Until(()=>!Flow.IsBusy);Check(Flow.Game.State.signinDays==3&&Flow.Game.State.signinClaimed.Take(3).All(n=>n==1),"Sign-in state lost on reattach");
|
|
return "PASS earned unclaimed login rewards remain, future day locked, lost-ack +5 granted once with receipt and durable journal cleared; profile reattach retains claims.";
|
|
}
|
|
public static async Task<string> Completed()
|
|
{
|
|
await SyncHome();Click("Daily");await Until(()=>Flow.Page=="UI_PrototypeSignin");Check(Flow.Game.State.signinDays==7&&!Dot("Dot_Daily")&&Enumerable.Range(0,7).All(i=>!Button("Signin"+i).interactable),"Completed seven-day course restarted");await Capture("signin_complete");
|
|
return "PASS completed seven-day view has all rewards claimed, no red dot and no repeated course.";
|
|
}
|
|
public static async Task<string> FinalViews()
|
|
{
|
|
await SyncHome();Click("Tasks");await Until(()=>Flow.Page=="UI_PrototypeTasks");Check(Enumerable.Range(0,3).All(i=>!Button("ClaimDaily"+i).interactable)&&!Dot("Dot_Tasks"),"Final daily claim state wrong");await Capture("tasks_claimed");
|
|
Click("ToSignin");await Until(()=>Flow.Page=="UI_PrototypeSignin");Check(Enumerable.Range(0,7).All(i=>!Button("Signin"+i).interactable)&&!Dot("Dot_Daily"),"Final sign-in claim state wrong");await Capture("signin_complete");
|
|
Click("Back");await Until(()=>Flow.Page=="Home");await Capture("home_claimed");return "PASS final task/sign-in copy, disabled claimed rewards and cleared home dots.";
|
|
}
|
|
}
|