174 lines
9.1 KiB
C#
174 lines
9.1 KiB
C#
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 <VSClone> -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<string> notes = new List<string>();
|
|
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);
|
|
}
|
|
|
|
// 유닛 애니 재생 검증: -executeMethod VS.EditorTools.EditorRender.AnimSeq → animseq/f##.png(0.2초 간격) + frames.txt(틱마다 유닛별 상태·프레임 이름)
|
|
public static void AnimSeq()
|
|
{
|
|
int exit = 0;
|
|
try
|
|
{
|
|
Application.SetStackTraceLogType(LogType.Log, StackTraceLogType.None);
|
|
fails = 0; notes.Clear();
|
|
string dir = Path.Combine(OutDir, "animseq"); Directory.CreateDirectory(dir);
|
|
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
|
var app = NewApp(); Progress(app.G); app.RebuildStage(); app.RefreshAll();
|
|
app.G.S.battleSlots = 6;
|
|
app.SwitchTab(1); app.RefreshAll();
|
|
app.BattleTest = new BattleSetup { mapType = 0, obstacles = 0, castleX = 9f, shots = new List<string>(), gimmicks = new List<string>() };
|
|
app.NewBattleRound(11); app.B.Start(); app.B.MaxMana = 99;
|
|
for (int s = 0; s < 6; s++) { app.B.Mana = 99; app.DeployCard(s); }
|
|
GameApp.AnimDtOverride = 0.1f;
|
|
var sb = new System.Text.StringBuilder();
|
|
int shots = 0, atkShots = 0;
|
|
// 틱 400~429 = 전 유닛 기절(정지) → 대기(idle) 클립 순환 검증(2026-10-30 ③ 원화 스타일 대기 루프 · vs_animseq_check idle 판정)
|
|
for (int i = 0; i < 430; i++)
|
|
{
|
|
if (i >= 400) foreach (var u in app.B.Units) u.stun = 1f;
|
|
app.DebugTick(0.1f, 1);
|
|
var imgs = new Dictionary<string, Image>();
|
|
foreach (var im in app.BattleRoot.GetComponentsInChildren<Image>(false)) imgs[im.name] = im;
|
|
var line = new List<string>();
|
|
foreach (var u in app.B.Units)
|
|
{
|
|
imgs.TryGetValue("U" + u.uid, out var im);
|
|
line.Add($"{u.def.id}/{u.uid}:{(u.attacking ? "A" : "w")}cd={u.cd:F2}:{(im != null && im.sprite != null ? im.sprite.name : "null")}");
|
|
}
|
|
sb.AppendLine($"t={i * 0.1f:F1} " + string.Join(" ", line));
|
|
// 촬영 = 걷기 처음 2 초(10장) + 근접 유닛(id 1·3·5)이 공격 중인 틱 40장(0.2 초 간격 · 근접은 성까지 20 초 넘게 걸림)
|
|
bool meleeAtk = false; foreach (var u in app.B.Units) if (u.attacking && !u.def.flying && u.def.range < 2f) meleeAtk = true;
|
|
if (i % 2 == 0 && (i < 20 || (meleeAtk && atkShots < 40))) { if (i >= 20) atkShots++; Shot(app, "animseq/f" + (shots++).ToString("D2") + "_t" + (i * 0.1f).ToString("F1")); }
|
|
}
|
|
File.WriteAllText(Path.Combine(dir, "frames.txt"), sb.ToString());
|
|
GameApp.AnimDtOverride = -1f;
|
|
Debug.Log($"[VS] RENDER ANIMSEQ DONE shots={shots} fails={fails}");
|
|
foreach (var n in notes) Debug.Log("[VS] RENDER NOTE " + n);
|
|
}
|
|
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<GameApp>();
|
|
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<Image>(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<Text>(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}");
|
|
}
|
|
}
|
|
}
|