137 lines
5.6 KiB
C#
137 lines
5.6 KiB
C#
|
|
using System.Collections;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace TKS.OutGame
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 시나리오 이벤트 검증 캡처(2026-11-12 · 개발 요청서 C1·C2) — 에디터 `TKS.EditorTools.ScenarioCapture.Run` 이 SessionState 로 넘기면 생성.
|
||
|
|
/// ① 스테이지 팝업(전장 설명 칸) ② 보스 스테이지마다 등장 연출을 정해진 시각에 찍고 아군 차례가 되면 1장 더 · 세이브 = 메모리 전용 신규 유저.
|
||
|
|
/// </summary>
|
||
|
|
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<string> log = new List<string>();
|
||
|
|
|
||
|
|
#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<ScenarioCaptureDriver>();
|
||
|
|
drv.dir = d;
|
||
|
|
drv.popups = Split(UnityEditor.SessionState.GetString(PopupKey, ""));
|
||
|
|
drv.stages = Split(UnityEditor.SessionState.GetString(StagesKey, ""));
|
||
|
|
var ts = new List<float>();
|
||
|
|
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
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|