using System; using System.Linq; using System.Reflection; using System.IO; using AOT.Boot; using HotUpdate.Net; using Newtonsoft.Json; using UnityEditor; using UnityEngine; using UnityEngine.UI; public static class VerifyMiniGameNetwork { static string Output => Path.GetFullPath(Path.Combine(Application.dataPath, "../../Tools/output/minigame_network")); public static string ExportNow() { Check(!EditorApplication.isPlaying && !BuildPipeline.isBuildingPlayer); Directory.CreateDirectory(Output); // Remove an earlier background queue if the unfocused editor never pumped delayCall. foreach (var callback in EditorApplication.delayCall?.GetInvocationList() ?? Array.Empty()) if (callback.Method.DeclaringType.Assembly.GetName().Name.StartsWith("PipelineRunScript_VerifyMiniGameNetwork", StringComparison.Ordinal)) EditorApplication.delayCall -= (EditorApplication.CallbackFunction)callback; SaveExport("building", null); try { string result = AOT.Editor.WeChat.ExportWeChatBasePackage.Export(); SaveExport(result.StartsWith("ok", StringComparison.Ordinal) ? "completed" : "failed", result); return result; } catch (Exception error) { SaveExport("failed", error.ToString()); throw; } } static void SaveExport(string status, string result) => File.WriteAllText(Path.Combine(Output, "export.json"), JsonConvert.SerializeObject(new { status, result, utc = DateTime.UtcNow }, Formatting.Indented)); public static string StageHotUpdate() { string result = AOT.Editor.YooAssetTools.BuildAndStageHotUpdate.BuildAndStage(); if (!result.StartsWith("ok", StringComparison.Ordinal)) throw new Exception(result); HybridCLR.Editor.Commands.LinkGeneratorCommand.GenerateLinkXml(EditorUserBuildSettings.activeBuildTarget); return result; } public static string CheckUiReady() { var gameplay = UnityEngine.Object.FindObjectOfType(); Check(gameplay != null); var ctx = (BootContext)typeof(HotUpdate.Gameplay.GameplayBootstrap) .GetField("_ctx", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(gameplay); Check(ctx != null && ctx.MainUiReady && string.IsNullOrEmpty(ctx.MainUiError)); Check(HotUpdate.UI.UiManager.Instance.Get("UI_MainHUD") != null); return "PASS: authored home prefab loaded and signalled readiness independently of network login"; } public static string Endpoints() { const string http = BootSettings.ProductionHttpBase; const string ws = BootSettings.ProductionWsTemplate; Check(AuthApi.DefaultHttpBase == "https://BuddyDefense.xworld.ren:15888"); Check(GameNet.ResolveRemoteEndpoint("https://game.xworld.ren", "https", http) == http); Check(GameNet.ResolveRemoteEndpoint("wss://game.xworld.ren/ws?pid={pid}&token={token}", "wss", ws) == ws); Check(GameNet.ResolveRemoteEndpoint("http://127.0.0.1:8080", "https", http) == http); Check(GameNet.ResolveRemoteEndpoint("https://localhost:8080", "https", http) == http); Check(GameNet.ResolveRemoteEndpoint("https://[::1]:8080", "https", http) == http); Check(GameNet.ResolveRemoteEndpoint("https://dev.localhost", "https", http) == http); Check(GameNet.ResolveRemoteEndpoint("ws://127.0.0.1/ws", "wss", ws) == ws); Check(GameNet.ResolveRemoteEndpoint(ws, "wss", "invalid") == ws); Check(GameNet.ResolveRemoteEndpoint("https://custom.example/api", "https", http) == "https://custom.example/api"); Check(GameNet.ResolveRemoteEndpoint(null, "https", http) == http); var session = new SessionData { Pid = 9, Token = "a+b &c" }; string resolved = session.BuildWsUrl(); Check(resolved.StartsWith("wss://BuddyDefense.xworld.ren:15888/ws?pid=9&token=")); Check(resolved.EndsWith("a%2Bb%20%26c")); return "PASS: local/insecure endpoints fall back; explicit secure remote endpoints preserved"; } public static string SceneStatus() => JsonConvert.SerializeObject(new { playing = EditorApplication.isPlaying, boot = UnityEngine.Object.FindObjectsOfType().Select(b => new { b.name, b.enabled }).ToArray(), canvases = UnityEngine.Object.FindObjectsOfType().Select(c => new { c.name, c.enabled, c.renderMode, c.sortingOrder, active = c.gameObject.activeInHierarchy, camera = c.worldCamera != null ? c.worldCamera.name : null }).ToArray(), cameras = UnityEngine.Object.FindObjectsOfType().Select(c => new { c.name, c.enabled, c.depth, c.cullingMask, target = c.targetTexture != null ? c.targetTexture.name : null }).ToArray() }); static void Check(bool ok) { if (!ok) throw new Exception("Endpoint regression"); } }