174 lines
10 KiB
C#
174 lines
10 KiB
C#
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<UnityEngine.SceneManagement.SceneManager.sceneCount; i++)
|
|
if (UnityEngine.SceneManagement.SceneManager.GetSceneAt(i).isDirty) throw new Exception("Existing scene has unsaved changes.");
|
|
if (!string.IsNullOrEmpty(SessionState.GetString(SceneKey, ""))) throw new Exception("Restore prior preview first.");
|
|
SessionState.SetString(SceneKey, JsonConvert.SerializeObject(EditorSceneManager.GetSceneManagerSetup()));
|
|
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
|
return Resolution(1080,1920,true);
|
|
}
|
|
public static string Restore()
|
|
{
|
|
if (EditorApplication.isPlaying) throw new Exception("Stop Play Mode first.");
|
|
string saved = SessionState.GetString(SceneKey, "");
|
|
if (string.IsNullOrEmpty(saved)) throw new Exception("No scene setup saved.");
|
|
EditorSceneManager.RestoreSceneManagerSetup(JsonConvert.DeserializeObject<SceneSetup[]>(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<count;i++)
|
|
{
|
|
var size = group.GetType().GetMethod("GetGameViewSize").Invoke(group,new object[]{i});
|
|
if ((int)size.GetType().GetProperty("width").GetValue(size)==width && (int)size.GetType().GetProperty("height").GetValue(size)==height) { index=i;break; }
|
|
}
|
|
if(index==count)
|
|
{
|
|
var size = Activator.CreateInstance(editor.GetType("UnityEditor.GameViewSize"),new object[]{Enum.ToObject(editor.GetType("UnityEditor.GameViewSizeType"),1),width,height,"Startup "+width+"x"+height});
|
|
group.GetType().GetMethod("AddCustomSize").Invoke(group,new[]{size});
|
|
}
|
|
selected.SetValue(window,index);window.Repaint();
|
|
return "Preview resolution "+width+"x"+height;
|
|
}
|
|
public static string Start()
|
|
{
|
|
if (!EditorApplication.isPlaying) throw new Exception("Enter Play Mode first.");
|
|
Application.runInBackground = true;
|
|
var camera = new GameObject("StartupPreviewCamera", typeof(Camera)).GetComponent<Camera>();
|
|
camera.clearFlags = CameraClearFlags.SolidColor;
|
|
camera.backgroundColor = new Color(.54f, .72f, .76f);
|
|
camera.cullingMask = 0;
|
|
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(BuildBootLoading.PrefabPath);
|
|
var view = BootPatchView.Create(prefab.GetComponent<BootPatchView>());
|
|
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<BootPatchView>();
|
|
if (view == null) throw new Exception("Loading preview missing.");
|
|
var texts = view.GetComponentsInChildren<TMP_Text>();
|
|
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<UnityEngine.UI.Image>();
|
|
var canvas = view.GetComponent<RectTransform>();
|
|
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<BootPatchView>();
|
|
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<BootPatchView>().GetComponent<Canvas>();
|
|
var camera = GameObject.Find("StartupPreviewCamera").GetComponent<Camera>();
|
|
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<<LayerMask.NameToLayer("UI");
|
|
canvas.renderMode=RenderMode.ScreenSpaceCamera;canvas.worldCamera=camera;canvas.planeDistance=1;
|
|
Canvas.ForceUpdateCanvases();camera.Render();RenderTexture.active=target;
|
|
pixels.ReadPixels(new Rect(0,0,width,height),0,0);pixels.Apply();
|
|
Directory.CreateDirectory(Output);File.WriteAllBytes(path,pixels.EncodeToPNG());
|
|
}
|
|
finally
|
|
{
|
|
RenderTexture.active=previous;camera.targetTexture=null;camera.cullingMask=mask;
|
|
canvas.renderMode=mode;canvas.worldCamera=worldCamera;canvas.planeDistance=plane;Canvas.ForceUpdateCanvases();
|
|
target.Release();UnityEngine.Object.Destroy(target);UnityEngine.Object.Destroy(pixels);
|
|
}
|
|
return path;
|
|
}
|
|
public static string CheckHidden()
|
|
{
|
|
if (UnityEngine.Object.FindObjectOfType<BootPatchView>() != null) throw new Exception("Fade did not finish.");
|
|
return "PASS: full progress and fade completed; loading overlay inactive.";
|
|
}
|
|
}
|