using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; namespace TKS.OutGame { /// /// 시나리오 이벤트 검증 캡처(2026-11-12 · 개발 요청서 C1·C2) — 에디터 `TKS.EditorTools.ScenarioCapture.Run` 이 SessionState 로 넘기면 생성. /// ① 스테이지 팝업(전장 설명 칸) ② 보스 스테이지마다 등장 연출을 정해진 시각에 찍고 아군 차례가 되면 1장 더 · 세이브 = 메모리 전용 신규 유저. /// public class ScenarioCaptureDriver : MonoBehaviour { public const string DirKey = "TKS_SC_CAPTURE_DIR"; public const string PopupKey = "TKS_SC_CAPTURE_POPUPS"; public const string StagesKey = "TKS_SC_CAPTURE_STAGES"; public const string TimesKey = "TKS_SC_CAPTURE_TIMES"; const int W = 1080, H = 1920; string dir; string[] popups = new string[0], stages = new string[0]; float[] times = new float[0]; readonly List log = new List(); #if UNITY_EDITOR [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] static void AutoSpawn() { string d = UnityEditor.SessionState.GetString(DirKey, ""); if (string.IsNullOrEmpty(d)) return; UnityEditor.SessionState.EraseString(DirKey); var drv = new GameObject("ScenarioCaptureDriver").AddComponent(); drv.dir = d; drv.popups = Split(UnityEditor.SessionState.GetString(PopupKey, "")); drv.stages = Split(UnityEditor.SessionState.GetString(StagesKey, "")); var ts = new List(); foreach (var t in Split(UnityEditor.SessionState.GetString(TimesKey, ""))) { float v; if (float.TryParse(t, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out v)) ts.Add(v); } drv.times = ts.ToArray(); } #endif static string[] Split(string s) { return s.Split(new[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries); } static int Index(BattleManager b, string cs) { var p = cs.Split('-'); int c, s; if (p.Length != 2 || !int.TryParse(p[0], out c) || !int.TryParse(p[1], out s)) return -1; for (int i = 0; i < b.Config.stages.Length; i++) if (b.Config.stages[i].chapter == c && b.Config.stages[i].stage == s) return i; return -1; } IEnumerator Start() { Directory.CreateDirectory(dir); yield return null; yield return null; var root = OutGameRoot.Instance; var cam = Camera.main; if (root == null || cam == null) { Log("FAIL: OutGameRoot 또는 카메라 없음"); Finish(1); yield break; } var bm = root.Battle; foreach (var cs in popups) { int si = Index(bm, cs.Trim()); if (si < 0) { Log("FAIL: 스테이지 없음 " + cs); continue; } root.OpenWorldMap(); yield return new WaitForSecondsRealtime(0.4f); root.Map.Show(bm.Config.stages[si].chapter - 1); yield return new WaitForSecondsRealtime(0.3f); root.Map.OpenPopup(bm.Config.stages[si].stage - 1); yield return new WaitForSecondsRealtime(0.4f); yield return Shot(cam, "popup_" + cs.Trim()); } foreach (var cs in stages) { int si = Index(bm, cs.Trim()); if (si < 0) { Log("FAIL: 스테이지 없음 " + cs); continue; } root.Map.EnterStage(bm.Config.stages[si].chapter - 1, bm.Config.stages[si].stage - 1); float t0 = Time.realtimeSinceStartup; foreach (var t in times) { while (Time.realtimeSinceStartup - t0 < t) yield return null; yield return Shot(cam, "intro_" + cs.Trim() + "_" + t.ToString("0.0", System.Globalization.CultureInfo.InvariantCulture) + "s"); } while (bm.Phase != BattlePhase.PlayerTurn && Time.realtimeSinceStartup - t0 < 20f) yield return null; Log("intro " + cs + " → 아군 차례까지 " + (Time.realtimeSinceStartup - t0).ToString("0.00") + "초 · phase=" + bm.Phase); yield return new WaitForSecondsRealtime(0.8f); yield return Shot(cam, "intro_" + cs.Trim() + "_end"); bm.GoIdle(); root.OpenWorldMap(); yield return new WaitForSecondsRealtime(0.5f); } Log("scenario errors=" + ScenarioData.Errors.Count); foreach (var e in ScenarioData.Errors) Log(" " + e); Finish(0); } IEnumerator Shot(Camera cam, string name) { string file = Path.Combine(dir, name + ".png"); yield return CaptureUtil.Capture(cam, W, H, file); Log("shot " + file); } void Log(string s) { log.Add(s); Debug.Log("[TKS-SC] " + s); try { File.WriteAllLines(Path.Combine(dir, "scenario_capture_log.txt"), log.ToArray()); } catch { } } void Finish(int code) { Log("finish code=" + code); #if UNITY_EDITOR UnityEditor.EditorApplication.Exit(code); #else Application.Quit(code); #endif } } }