using System; using System.IO; using System.Linq; using System.Reflection; using AIGame.EditorTools; using AOT.UI; using Newtonsoft.Json; using TMPro; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; public static class VerifyStartupPresentation { static string Output => Path.GetFullPath(Path.Combine(Application.dataPath, "../../Tools/output/startup_presentation")); public static string Build() => BuildBootLoading.Build(); public static string Export() { if (EditorApplication.isPlaying || BuildPipeline.isBuildingPlayer) throw new Exception("Editor must be idle."); if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.WebGL) throw new Exception("Expected WebGL target."); if (BuildBootLoading.ValidateConfigured() != null) throw new Exception(BuildBootLoading.ValidateConfigured()); Directory.CreateDirectory(Output); string file = Path.Combine(Output,"export.json"); File.WriteAllText(file,JsonConvert.SerializeObject(new {status="building",utc=DateTime.UtcNow})); try { string result = AOT.Editor.WeChat.ExportWeChatBasePackage.Export(); bool passed = result.StartsWith("ok minigame=",StringComparison.Ordinal); File.WriteAllText(file,JsonConvert.SerializeObject(new {status=passed?"completed":"failed",result,utc=DateTime.UtcNow},Formatting.Indented)); if (!passed) throw new Exception(result); return result; } catch(Exception error) { File.WriteAllText(file,JsonConvert.SerializeObject(new {status="failed",error=error.ToString(),utc=DateTime.UtcNow},Formatting.Indented)); throw; } } const string SceneKey = "AIGame.StartupPresentation.Setup"; public static string Prepare() { if (EditorApplication.isPlaying) throw new Exception("Stop Play Mode first."); for (int i=0; i(saved)); var type = typeof(Editor).Assembly.GetType("UnityEditor.GameView"); var window = EditorWindow.GetWindow(type); type.GetProperty("selectedSizeIndex", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic) .SetValue(window,SessionState.GetInt(SceneKey+".Size",0)); window.Repaint(); SessionState.EraseString(SceneKey); return "Original scenes and Game View restored."; } public static string Phone() => Resolution(1080,2338,false); public static string Plain() => Resolution(1080,1920,false); static string Resolution(int width, int height, bool remember) { var editor = typeof(Editor).Assembly; var type = editor.GetType("UnityEditor.GameView"); var window = EditorWindow.GetWindow(type); var selected = type.GetProperty("selectedSizeIndex",BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); if (remember) SessionState.SetInt(SceneKey+".Size",(int)selected.GetValue(window)); var sizesType = editor.GetType("UnityEditor.GameViewSizes"); var sizes = typeof(ScriptableSingleton<>).MakeGenericType(sizesType).GetProperty("instance").GetValue(null); var group = sizesType.GetMethod("GetGroup").Invoke(sizes,new[]{sizesType.GetProperty("currentGroupType").GetValue(sizes)}); int count = (int)group.GetType().GetMethod("GetTotalCount").Invoke(group,null), index=count; for (int i=0;i(); camera.clearFlags = CameraClearFlags.SolidColor; camera.backgroundColor = new Color(.54f, .72f, .76f); camera.cullingMask = 0; var prefab = AssetDatabase.LoadAssetAtPath(BuildBootLoading.PrefabPath); var view = BootPatchView.Create(prefab.GetComponent()); view.SetStatus("正在布置营地…"); view.SetProgress(.76f); return "Preview started from the real local prefab; no network requests."; } public static string Check() { var view = UnityEngine.Object.FindObjectOfType(); if (view == null) throw new Exception("Loading preview missing."); var texts = view.GetComponentsInChildren(); foreach (var text in texts) { text.ForceMeshUpdate(); if (!text.font.HasCharacters(text.text)) throw new Exception("Missing glyphs: " + text.text); if (text.isTextOverflowing) throw new Exception("Text overflow: " + text.name); } var image = view.transform.Find("Artwork").GetComponent(); var canvas = view.GetComponent(); var art = (RectTransform)image.transform; if (art.rect.width + 1 < canvas.rect.width || art.rect.height + 1 < canvas.rect.height) throw new Exception("Artwork does not cover the viewport."); float ratio = image.sprite.rect.width / image.sprite.rect.height; if (Mathf.Abs(art.rect.width / art.rect.height - ratio) > .001f) throw new Exception("Artwork stretched."); var font = texts[0].font; if (font.atlasPopulationMode != AtlasPopulationMode.Static || font.sourceFontFile != null) throw new Exception("Boot font must not depend on runtime glyph generation."); float shown = (float)typeof(BootPatchView).GetField("_shown", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(view); view.SetProgress(.1f); float target = (float)typeof(BootPatchView).GetField("_target", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(view); if (target < .75f) throw new Exception("Progress moved backward."); Directory.CreateDirectory(Output); string report = JsonConvert.SerializeObject(new { passed=true, screen=new [] {Screen.width,Screen.height}, chineseGlyphs=true, noTextOverflow=true, aspectPreserved=true, progressMonotonic=true, shown, target, splash=PlayerSettings.SplashScreen.show, fontAtlas=new[]{font.atlasWidth,font.atlasHeight}, bootReference=BuildBootLoading.ValidateConfigured() }, Formatting.Indented); File.WriteAllText(Path.Combine(Output, "validation-" + Screen.width + "x" + Screen.height + ".json"), report); return report; } public static string Complete() { var view = UnityEngine.Object.FindObjectOfType(); view.SetStatus("准备就绪,即将出发"); view.SetProgress(1f); view.Hide(); return "Fade requested; inspect completion on the following frames."; } public static string Capture() { var canvas = UnityEngine.Object.FindObjectOfType().GetComponent(); var camera = GameObject.Find("StartupPreviewCamera").GetComponent(); var mode = canvas.renderMode; var worldCamera = canvas.worldCamera; float plane = canvas.planeDistance; var previous = RenderTexture.active; int mask = camera.cullingMask; int width = Screen.width, height = Screen.height; var target = new RenderTexture(width,height,24); var pixels = new Texture2D(width,height,TextureFormat.RGB24,false); string path = Path.Combine(Output,"loading-"+width+"x"+height+".png"); try { camera.targetTexture=target; camera.cullingMask=1<() != null) throw new Exception("Fade did not finish."); return "PASS: full progress and fade completed; loading overlay inactive."; } }