using System; using System.Collections.Generic; using System.IO; using System.Numerics; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.UI; using VS.Sim; using VS.View; namespace VS.EditorTools { // 화면 렌더 검사: Unity.exe -batchmode(그래픽 켬) -projectPath -executeMethod VS.EditorTools.EditorRender.Run // → C:/ViralStreamer/_re/render/*.png · 임시 세이브 사용(PD 세이브 미접촉) · 결과 "RENDER ALL PASS" 또는 "RENDER FAIL n" public static partial class EditorRender { public const string OutDir = "C:/ViralStreamer/_re/render"; static int fails; static readonly List notes = new List(); static DateTime clockBase = new DateTime(2026, 1, 1, 12, 0, 0); static double clockExtra; public static void Run() { int exit = 0; try { Application.SetStackTraceLogType(LogType.Log, StackTraceLogType.None); fails = 0; notes.Clear(); Directory.CreateDirectory(OutDir); EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); var app = NewApp(); Shot(app, "main_new"); Progress(app.G); app.RebuildStage(); app.RefreshAll(); Shot(app, "main_mid"); app.OpenHouse(); Shot(app, "pop_house"); app.ClosePopup(); app.OpenSkill(); Shot(app, "pop_skill"); app.ClosePopup(); app.OpenCloset(); Shot(app, "pop_closet"); app.ClosePopup(); if (app.G.Story != null && app.G.Story.chapters.Count > 0) { app.OpenStory(app.G.Story.chapters[0]); Shot(app, "pop_story"); app.ClosePopup(); } app.G.CoinDonate = 1234.5m; app.RefreshAll(); app.OpenClaimDonate(); Shot(app, "pop_donate"); app.ClosePopup(); app.OpenSettings(); Shot(app, "pop_settings"); app.ClosePopup(); app.G.Follower = app.T.RankFollower[3]; app.OpenRankUp(); Shot(app, "pop_rankup"); app.ClosePopup(); SystemShots(app); // 방 6종 최대 단계 그림 for (int h = 0; h < Tables.HouseCount; h++) { app.G.S.house = h; app.G.S.rooms.Clear(); foreach (var it in app.T.Rooms[h].Items) app.G.S.rooms.Add(new SaveItem { Type = it.Index, Level = it.Levels.Count - 1 }); app.RebuildStage(); app.RefreshAll(); Shot(app, "room" + (h + 1) + "_max"); } Debug.Log(fails == 0 ? "[VS] RENDER ALL PASS" : $"[VS] RENDER FAIL {fails}"); foreach (var n in notes) Debug.Log("[VS] RENDER NOTE " + n); if (fails > 0) exit = 1; } catch (Exception e) { Debug.LogError("[VS] RENDER EXCEPTION " + e); exit = 2; } EditorApplication.Exit(exit); } static RenderTexture rt; static GameApp NewApp() { clockExtra = 0; GameApp.ClockOverride = () => clockBase.AddSeconds(clockExtra); GameApp.SavePathOverride = Path.Combine(Path.GetTempPath(), "vs_render_save.json"); if (File.Exists(GameApp.SavePathOverride)) File.Delete(GameApp.SavePathOverride); rt = new RenderTexture(1080, 1920, 24, RenderTextureFormat.ARGB32); GameApp.RenderTarget = rt; var go = new GameObject("Game"); var app = go.AddComponent(); app.Headless = true; app.Init(); return app; } public static void Advance(double sec) => clockExtra += sec; /// 중반 진행 상태 (방 1 아이템 일부 · 스킬 · 랭크 3 · 의상 5) static void Progress(Game g) { g.S.rooms.Clear(); int[] lv = { 30, 26, 52, 12, 74, 20, 8, 40, 60, 3, 50 }; for (int i = 0; i < lv.Length; i++) g.S.rooms.Add(new SaveItem { Type = i, Level = lv[i] }); g.S.skills.Clear(); for (int i = 0; i < 5; i++) g.S.skills.Add(new SaveItem { Type = i, Level = 10 + i * 7 }); g.Follower = BigInteger.Parse("250000"); g.S.rankIndex = 3; g.Coin = BigInteger.Parse("12345678"); g.S.ticket = 7; g.S.closetLevel = 5; g.S.closetCurrent = 3; g.CoinDonate = 456.7m; } static void Shot(GameApp app, string name) { Canvas.ForceUpdateCanvases(); app.Cam.targetTexture = rt; app.Cam.Render(); Canvas.ForceUpdateCanvases(); app.Cam.Render(); var prev = RenderTexture.active; RenderTexture.active = rt; var tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false); tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); tex.Apply(); RenderTexture.active = prev; File.WriteAllBytes(Path.Combine(OutDir, name + ".png"), tex.EncodeToPNG()); UnityEngine.Object.DestroyImmediate(tex); // 검사: 빈 그림 · 글자 넘침 int missing = 0, overflow = 0; foreach (var im in app.Root.GetComponentsInChildren(false)) if (im.sprite == null && im.color.a > 0.01f && im.enabled) { missing++; if (missing <= 3) notes.Add(name + " 빈 Image: " + im.name); } foreach (var t in app.Root.GetComponentsInChildren(false)) { if (string.IsNullOrEmpty(t.text) || !t.enabled) continue; var gen = t.cachedTextGenerator; if (gen.characterCountVisible > 0 && gen.characterCountVisible < t.text.Replace("\n", "").Length - 1) overflow++; } if (missing > 0) { fails++; notes.Add($"{name}: 그림 없는 Image {missing}"); } if (overflow > 0) notes.Add($"{name}: 잘린 글자 {overflow}"); Debug.Log($"[VS] RENDER {name} missing={missing} cut={overflow}"); } } }