132 lines
8.3 KiB
C#
132 lines
8.3 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 UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
/// <summary>Play Mode check that PrototypeArena loads Greenfield without bridges.</summary>
|
|
public static class VerifyBattlefield
|
|
{
|
|
const string Endpoint = "http://127.0.0.1:18081";
|
|
static PrototypeFlow Flow => UnityEngine.Object.FindObjectOfType<PrototypeFlow>();
|
|
static void Check(bool value, string message) { if (!value) throw new Exception(message); }
|
|
static T Get<T>(string name) => (T)typeof(PrototypeFlow).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(Flow);
|
|
static void Set(string name, object value) => typeof(PrototypeFlow).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(Flow, value);
|
|
static async Task Until(Func<bool> condition, int seconds = 25)
|
|
{
|
|
var end = DateTime.UtcNow.AddSeconds(seconds);
|
|
while (!condition())
|
|
{
|
|
Check(DateTime.UtcNow < end, "Battlefield 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, "Blocked " + name);
|
|
ExecuteEvents.Execute(b.gameObject, pointer, ExecuteEvents.pointerClickHandler);
|
|
}
|
|
static async Task Capture(string name)
|
|
{
|
|
await Task.Delay(200);
|
|
var type = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetType("Unity.Pipeline.Editor.Commands.Capture.CaptureCommands")).First(t => t != null);
|
|
type.GetMethod("CaptureGameView", BindingFlags.Public | BindingFlags.Static).Invoke(null, new object[] { 1080, 1920, null, "Screenshots/battlefield_" + name + ".png", false, 0, "screen" });
|
|
}
|
|
|
|
public static string Assets()
|
|
{
|
|
var arena = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Bundles/Scenes/Prototype/PrototypeArena.prefab");
|
|
Check(arena != null, "Missing PrototypeArena");
|
|
Check(arena.transform.Find("Greenfield") != null, "PrototypeArena missing Greenfield");
|
|
Check(arena.transform.Find("Greenfield/Ground/GroundMesh") != null, "Missing Greenfield ground");
|
|
Check(arena.transform.Find("Greenfield/Decorations/tree") != null, "Missing tree");
|
|
Check(arena.transform.Find("Greenfield/Decorations/rock") != null, "Missing rock");
|
|
Check(arena.transform.Find("Greenfield/Decorations/sign") != null, "Missing sign");
|
|
Check(arena.transform.Find("Greenfield/Decorations/shrub") != null, "Missing shrub");
|
|
Check(arena.transform.Find("Greenfield/Decorations/bridge") == null, "bridge still nested");
|
|
Check(arena.transform.Find("Greenfield/Decorations/bridgeLeft") == null, "bridgeLeft still nested");
|
|
Check(arena.transform.Find("Greenfield/Decorations/bridgeRight") == null, "bridgeRight still nested");
|
|
Check(arena.transform.Find("Heroes") != null && arena.transform.Find("BattleCamera") != null, "Gameplay nodes missing");
|
|
var ground = arena.transform.Find("Ground");
|
|
Check(ground == null || !ground.gameObject.activeSelf, "Primitive ground still active");
|
|
var badLayer = arena.transform.Find("Greenfield").GetComponentsInChildren<Renderer>(true).FirstOrDefault(r => r.gameObject.layer != 30);
|
|
Check(badLayer == null, "Greenfield renderer not on layer 30: " + badLayer?.name);
|
|
return "PASS authored PrototypeArena nests Greenfield without bridges.";
|
|
}
|
|
|
|
public static async Task<string> Play()
|
|
{
|
|
Check(EditorApplication.isPlaying, "Enter Play Mode first");
|
|
await Until(() => Flow?.Game != null && !Flow.IsBusy);
|
|
SessionState.SetString("AIGame.Battlefield.original", JsonUtility.ToJson(Flow.Game.State));
|
|
SessionState.SetString("AIGame.Battlefield.originalEndpoint", Get<string>("_httpBase"));
|
|
AuthResponse account = null; string error = null; bool done = false;
|
|
string user = "battlefield_" + Guid.NewGuid().ToString("N");
|
|
Directory.CreateDirectory(Path.Combine(Application.dataPath, "../../Tools/output/battlefield"));
|
|
File.WriteAllText(Path.Combine(Application.dataPath, "../../Tools/output/battlefield/account.txt"), user);
|
|
Flow.StartCoroutine(AuthApi.Register(Endpoint, user, "isolated-battlefield-password", (r, e) => { account = r; error = e; done = true; }));
|
|
await Until(() => done);
|
|
Check(account != null, "Isolated register failed " + error);
|
|
var session = new SessionData { Pid = account.pid, Token = account.token, Username = user };
|
|
UiManager.Instance.Get(ConfirmDialogView.PrefabName).GetComponent<ConfirmDialogView>().Hide();
|
|
Set("_session", new Func<SessionData>(() => session));
|
|
Set("_profile", new Func<long>(() => session.Pid));
|
|
Set("_httpBase", Endpoint);
|
|
Set("_boundProfile", 0L);
|
|
PlayerPrefs.DeleteKey("AIGame.G1.pending." + Uri.EscapeDataString(Endpoint) + "." + session.Pid);
|
|
Flow.Handle("Home");
|
|
await Until(() => Flow.Game != null && !Flow.IsBusy);
|
|
Check(Flow.Game.State.formation != null && Flow.Game.State.formation.Any(p => p >= 0), "Fresh account has empty formation");
|
|
Click("Adventure");
|
|
await Until(() => Flow.Page == "UI_PrototypeStages");
|
|
Click("Stage1");
|
|
await Until(() => Flow.Page == "UI_PrototypeFormation");
|
|
Click("StartBattle");
|
|
await Until(() => Flow.Page == "UI_PrototypeBattle" && Flow.Battle != null);
|
|
var arena = Get<GameObject>("_arena");
|
|
Check(arena != null, "Battle arena was not instantiated");
|
|
Check(arena.transform.Find("Greenfield/Ground/GroundMesh") != null, "Runtime Greenfield ground missing");
|
|
Check(arena.transform.Find("Greenfield/Decorations/tree") != null, "Runtime tree missing");
|
|
Check(arena.transform.Find("Greenfield/Decorations/bridge") == null, "Runtime bridge present");
|
|
Check(arena.transform.Find("Greenfield/Decorations/bridgeLeft") == null, "Runtime bridgeLeft present");
|
|
Check(arena.transform.Find("Greenfield/Decorations/bridgeRight") == null, "Runtime bridgeRight present");
|
|
var ground = arena.transform.Find("Ground");
|
|
Check(ground == null || !ground.gameObject.activeSelf, "Runtime primitive ground still active");
|
|
Click("Speed");
|
|
await Until(() => Flow.Battle.Time >= 8);
|
|
await Capture("play_battle");
|
|
return "PASS play battle loads Greenfield without bridges; screenshot battlefield_play_battle.png";
|
|
}
|
|
|
|
public static async Task<string> Cleanup()
|
|
{
|
|
var net = UnityEngine.Object.FindObjectOfType<GameNet>();
|
|
UiManager.Instance.Get(ConfirmDialogView.PrefabName).GetComponent<ConfirmDialogView>().Hide();
|
|
Set("_session", new Func<SessionData>(() => net.Session));
|
|
Set("_profile", new Func<long>(() => net.Session?.Pid ?? 0));
|
|
Set("_httpBase", SessionState.GetString("AIGame.Battlefield.originalEndpoint", "http://127.0.0.1:8080"));
|
|
Set("_boundProfile", 0L);
|
|
Flow.Handle("Home");
|
|
await Until(() => Flow.Game != null && !Flow.IsBusy);
|
|
var original = JsonUtility.FromJson<PrototypeSave>(SessionState.GetString("AIGame.Battlefield.original", ""));
|
|
Check(Flow.Game.State.coins == original.coins && Flow.Game.State.candy == original.candy && Flow.Game.State.shots == original.shots && Flow.Game.State.level == original.level, "Real account was changed by battlefield test");
|
|
return "PASS cleanup: real account restored; battlefield check used isolated :18081 only.";
|
|
}
|
|
}
|