ThreeKingdomsSlingshot/Assets/Scripts/OutGame/OutGameCaptureDriver.cs

162 lines
6.8 KiB
C#
Raw Permalink Normal View History

아웃게임 1차(PD #1093 세션 A) — 본영 로비 · 세이브 · 군량 · 영웅(레벨·승급 6칸·진화·스킬 표시) · 편성(전열 3/후열 2 · 프리셋 3) · 거래(뽑기·골드 장비 상점) · 스테이지 보상·별 3·소탕 - 데이터: 기획 tables/ 12장 → Assets/Data/OutGame/*.csv · 메뉴 TKS/Import OutGame Data(Editor/DataImporter) → Resources/OutGame 9 자산(HeroDb·GearDb·GachaConfig·EconomyConfig·RewardTable·LevelTable·PromotionTable·EvolveTable·SkillInfoDb) · 검증(행 수·필수 열·id 유일·hero↔skill↔gear·확률 합) 오류 시 자산 불변 · BalanceConfig.heroes[]/HeroDef 삭제 → HeroDb(기존 5인 id 유지) · economy.csv 키 17 + gacha.csv 키 2 추가(기획서 본문 값 · C45) - 세이브: persistentDataPath/save.json · ver 1 · 즉시 저장 · 오프라인 군량 회복 · 일일 초기화 · 신규 유저 = 유비·관우·장비·조운·황충 Lv1 녹 ★=희귀도 · 골드 1000 · 보옥 300 · 군량 30 · 테스트·캡처 = 메모리 전용 - 화면(uGUI 와이어프레임 · img03·06·08·11): 시작 = 본영 로비(출정 → 월드맵 · 편성 · 연무장/보물/내정 준비 중 · 동맹 추후) · 재화 바(월드맵 포함 · 군량 타이머) · 하단 탭 5 · ◀/Esc 일관 · 영웅 목록·상세·상세정보·도감 · 편성(탭·드래그) · 뽑기(천장 n/80 · 확률 공개 · 첫 10연 무료 · 10연 ★★ 보장 · 카드 순차 공개) · 장비 상점(흰/녹 6종 일일 · sell×5 · 새로고침 보옥 20) - 전투 연결: BattleManager.LineupProvider/Deployed(LineupEntry · §3-2 스탯 · 방어 배율 생성 뒤) · playerSpawnPoints = 전열 (−4/0/4, −12) · 후열 (−2/2, −14) · WorldMapScreen 훅(팝업 군량·보상·별 · 입장 군량 · 노드 별 star_on/off · 소탕 · ◀ 본영 · TopInset) · 결과 패널(별 3 조건 · 골드·경험·보옥·장비) · GameBootstrap/AutoPlayDriver 로비 시작 - B 세션 파일(ActionResolver·Combat·UnitView·BattleHUD·SlingshotInput·EnemyAI) 미변경 - 테스트 56/56(기존 41 유지 · 신규 OutGameTests 15) · console error 0 · 사본 GUI 캡처 11장(DataImporter.CaptureOutGame) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 12:11:10 +00:00
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace TKS.OutGame
{
/// <summary>
/// 아웃게임 화면 검증 캡처(에디터 DataImporter.CaptureOutGame 이 SessionState 로 출력 폴더를 넘기면 생성 · 세이브 = 메모리 전용 신규 유저).
/// 로비 → 영웅 목록 → 영웅 상세(캡처용 장비 지급·장착) → 편성 → 뽑기 → 첫 10연(무료) 결과 → 상점 → 월드맵 팝업 → 전투(적 전원 처치) 결과 → 재방문 팝업.
/// </summary>
public class OutGameCaptureDriver : MonoBehaviour
{
public const string DirKey = "TKS_OUTGAME_CAPTURE_DIR";
public string OutputDir;
public int Width = 720;
public int Height = 1280;
readonly List<string> log = new List<string>();
int shot = 1;
#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
static void AutoSpawn()
{
string dir = UnityEditor.SessionState.GetString(DirKey, "");
if (string.IsNullOrEmpty(dir)) return;
UnityEditor.SessionState.EraseString(DirKey);
var d = new GameObject("OutGameCaptureDriver").AddComponent<OutGameCaptureDriver>();
d.OutputDir = dir;
}
#endif
IEnumerator Start()
{
Directory.CreateDirectory(OutputDir);
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 s = root.Session;
Log("memoryOnly=" + SaveStore.MemoryOnly + " newUser=" + s.IsNewUser + " gold=" + s.Save.gold + " gem=" + s.Save.gem + " stamina=" + s.Save.stamina +
" heroes=" + s.Save.heroes.Count + " preset=" + string.Join(",", s.Save.ActivePreset.slots.ToArray()));
yield return Wait();
yield return Shot(cam, "lobby");
root.Show(root.HeroList);
yield return Wait();
yield return Shot(cam, "hero_list");
// 영웅 상세: 두 번째 시작 영웅 · 캡처용 장비 지급(요구 장비 4칸분) → 3칸 장착 · 1칸 = 가방 보유 표시
var id = s.Db.Economy.StartHeroes.Length > 1 ? s.Db.Economy.StartHeroes[1] : s.Db.Economy.StartHeroes[0];
var h = s.Def(id);
var hs = s.Save.Hero(id);
for (int i = 0; i < 4; i++) s.Save.inv.AddGear(HeroRules.RequiredGear(s.Db, h, hs, i), 1);
for (int i = 0; i < 3; i++) Log("equip slot " + i + " → " + (s.Equip(id, i) ?? "ok"));
HeroRules.GrantExp(hs, s.Db.Levels.Get(1).expToNext + 5);
s.Commit();
root.ShowHero(id);
yield return Wait();
yield return Shot(cam, "hero_detail_" + id);
root.Show(root.Formation);
yield return Wait();
yield return Shot(cam, "formation");
root.Show(root.Trade);
root.Trade.SetPage(0);
yield return Wait();
yield return Shot(cam, "gacha");
root.Trade.DoDraw(s.Db.Gacha.TenCount);
yield return new WaitForSecondsRealtime(0.5f);
Log("gacha revealed(0.5s)=" + root.Trade.RevealedCount);
root.Trade.RevealAll();
yield return Wait();
var pulls = root.Trade.LastPulls;
var names = new List<string>();
if (pulls != null)
foreach (var p in pulls) names.Add(p.heroId + "★" + p.tier + (p.isNew ? "N" : p.shards > 0 ? "+" + p.shards : "+g" + p.gold));
Log("gacha 10 = " + string.Join(" ", names.ToArray()) + " · pity=" + s.Save.gacha.pity + " gem=" + s.Save.gem + " firstTenUsed=" + s.Save.gacha.firstTenUsed);
yield return Shot(cam, "gacha_result");
root.Trade.CloseResult();
root.Trade.SetPage(2);
yield return Wait();
yield return Shot(cam, "shop");
root.ShowLobby();
root.OpenWorldMap();
yield return Wait();
var wm = root.Map;
wm.OpenPopup(0);
yield return Wait();
yield return Shot(cam, "worldmap_popup");
int st0 = s.Save.stamina;
wm.ConfirmPopup();
var bm = root.Battle;
float t0 = Time.realtimeSinceStartup;
while (bm.Phase != BattlePhase.PlayerTurn && Time.realtimeSinceStartup - t0 < 10f) yield return null;
Log("battle players=" + bm.AliveCount(Faction.Player) + " enemies=" + bm.AliveCount(Faction.Enemy) + " stamina " + st0 + "→" + s.Save.stamina);
foreach (var u in bm.Units)
if (u != null && u.Faction == Faction.Player) Log(" " + u.DisplayName + " " + u.Type + " hp" + u.MaxHp + " atk" + u.Atk + " def" + u.Def + " @" + u.Position);
yield return new WaitForSecondsRealtime(0.6f);
yield return Shot(cam, "battle_start");
foreach (var e in bm.AliveUnits(Faction.Enemy)) e.TakeDamage(e.Hp); // 결과 화면 확인용(적 전원 처치)
bm.CheckBattleEnd();
yield return new WaitForSecondsRealtime(0.6f);
var r = s.LastReward;
Log("result phase=" + bm.Phase + " stars=" + (r != null ? r.stars : -1) + " gold+" + (r != null ? r.gold : 0) + " exp+" + (r != null ? r.exp : 0) + " gem+" + (r != null ? r.gem : 0) + " gear=" + (r != null ? r.gearId : ""));
yield return Shot(cam, "battle_result");
bm.ContinueAfterResult();
yield return Wait();
wm.OpenPopup(0);
yield return Wait();
yield return Shot(cam, "worldmap_revisit");
Finish(0);
}
static IEnumerator Wait()
{
yield return null;
yield return new WaitForSecondsRealtime(0.3f);
}
IEnumerator Shot(Camera cam, string name)
{
string file = Path.Combine(OutputDir, shot.ToString("00") + "_" + name + ".png");
shot++;
yield return CaptureUtil.Capture(cam, Width, Height, file);
Log("shot " + file);
}
void Log(string s)
{
log.Add(s);
Debug.Log("[OutGameCapture] " + s);
try
{
File.WriteAllLines(Path.Combine(OutputDir, "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
}
}
}