WL #947-2 테스트 씬 빠른 재시작 + 원본 가상패드 — Enter Play Mode 도메인·씬 리로드 끔(EditorSettings) · NavMesh 사전 베이크(WLSkillTestNavMesh.asset · 하네스 베이크 생략) · InGameInfo 예열 생략 훅(JSON preloadEffects 0) · 원본 HUD(NewGameUI) Floating Joystick 중첩 프리팹·캔버스 스케일·RectTransform 값을 읽어 복제(PD 「원본과 동일한 가상패드 + 키 입력」) · 글자 raycastTarget 끔 · WLWeaponClasses 정적 초기화(SubsystemRegistration) · 하네스 ResolveClass 가 Ensure() 먼저 · 패드 검증 훅 PadFor

실측: 연속 Play 버튼 → ready 3.1 s(이전 100~140 s) · 리컴파일 직후 첫 Play 63 s · 패드 입력 (1,0) → 3.9 m/1 s · 키 이동 5.7 m/1.5 s · 등급 6 Q/E 발동 · O/P 순환 · 콘솔 게임 오류 0(2회 연속 Play)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
깃 관리자 2026-10-20 10:24:45 +09:00
parent 0762f3e2b8
commit 3e7215ad34
9 changed files with 1533 additions and 1283 deletions

View File

@ -82,6 +82,10 @@ public partial class InGameInfo : MyCoroutine
while (!TableChecker.Ins.CheckAllLoad()) yield return new WaitForSeconds(0.1f); while (!TableChecker.Ins.CheckAllLoad()) yield return new WaitForSeconds(0.1f);
#if UNITY_EDITOR
if (WL.SkillTest.WLTestScene.Active && !WL.SkillTest.WLTestScene.PreloadEffects) yield break; // WL #947 훅 — 테스트 씬은 예열(인스턴스 514 · 한 프레임 약 18 s)을 생략하고 첫 사용 때 로드한다(JSON preloadEffects 1 이면 원본대로)
#endif
var lst = table_effectlist.Ins.Get_DataList(1); var lst = table_effectlist.Ins.Get_DataList(1);
for (int i = 0; i < lst.Count; i++) for (int i = 0; i < lst.Count; i++)
{ {

View File

@ -54,6 +54,10 @@ namespace WL.Combat.Weapon
static readonly HashSet<int> s_eventsDone = new HashSet<int>(); // 클립 인스턴스 ID static readonly HashSet<int> s_eventsDone = new HashSet<int>(); // 클립 인스턴스 ID
static readonly HashSet<int> s_overridden = new HashSet<int>(); // 수정이 끝난 기존 직업 ID static readonly HashSet<int> s_overridden = new HashSet<int>(); // 수정이 끝난 기존 직업 ID
static readonly HashSet<int> s_modelRefreshed = new HashSet<int>(); // 모델 재부착이 끝난 PC 인스턴스 ID static readonly HashSet<int> s_modelRefreshed = new HashSet<int>(); // 모델 재부착이 끝난 PC 인스턴스 ID
/// <summary>#947 Enter Play Mode 「도메인 리로드 끔」 대비 — Play 마다 표(table_classconfig)·PC 는 새 인스턴스인데 정적 「끝남」 표시가 남으면 수정 행·모델 재부착을 건너뛴다. 표 데이터(s_defs)는 에셋이라 그대로 둔다.</summary>
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void ResetStatics() { s_overridden.Clear(); s_modelRefreshed.Clear(); Injected = EventsAdded = Overridden = 0; }
static readonly List<WLWeaponOrient> s_orients = new List<WLWeaponOrient>(); // #834 무기 방향 보정 규칙 static readonly List<WLWeaponOrient> s_orients = new List<WLWeaponOrient>(); // #834 무기 방향 보정 규칙
public static int OrientApplied; public static int OrientApplied;

View File

@ -6,14 +6,17 @@
// · ResWork/UIPrefabs/Title/{Tables, SoundInfo, SortOrder_5(OptionInfo·Popup), ActorInfo}.prefab // · ResWork/UIPrefabs/Title/{Tables, SoundInfo, SortOrder_5(OptionInfo·Popup), ActorInfo}.prefab
// · ResWork/Prefabs/Ingame/{InGameInfo(이펙트·투사체 풀), ProjectileInfo, Main Camera(RealCamera)}.prefab // · ResWork/Prefabs/Ingame/{InGameInfo(이펙트·투사체 풀), ProjectileInfo, Main Camera(RealCamera)}.prefab
// · PCPos/치비 PC 프리팹(WLCharacterSwapSettings.pcPrefabName · 없으면 Ai01) · MobPos/더미 몹 프리팹(Res_Addr/Mobs/WL/RPG_Bat) // · PCPos/치비 PC 프리팹(WLCharacterSwapSettings.pcPrefabName · 없으면 Ai01) · MobPos/더미 몹 프리팹(Res_Addr/Mobs/WL/RPG_Bat)
// · Canvas + 글자 4(원본 Set_Dmglabel 이 쓰는 피해 로그) · WLSkillTestHarness(actors · labels · pcActor · dummyActor) // · Canvas(스케일 = 원본 NewGameUI 와 동일) + 원본 가상패드(Floating Joystick 중첩 프리팹 · RectTransform 값 = NewGameUI 의 것) + 글자 4(원본 Set_Dmglabel 이 쓰는 피해 로그)
// · Ground 의 NavMeshSurface(사전 베이크 · 데이터 에셋 WLSkillTestNavMesh.asset) · WLSkillTestHarness(actors · labels · pcActor · dummyActor)
// ■ 메뉴 WL/Skill Test/Build Scene · CLI: 먼저 CloseTestScene() 또는 Title 을 연 뒤 Build() // ■ 메뉴 WL/Skill Test/Build Scene · CLI: 먼저 CloseTestScene() 또는 Title 을 연 뒤 Build()
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────
using System.Text; using System.Text;
using TMPro; using TMPro;
using Unity.AI.Navigation;
using UnityEditor; using UnityEditor;
using UnityEditor.SceneManagement; using UnityEditor.SceneManagement;
using UnityEngine; using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityEngine.UI; using UnityEngine.UI;
@ -32,6 +35,8 @@ namespace WL.SkillTest.Editor
const string IngamePrefabFolder = "Assets/ResWork/Prefabs/Ingame/"; const string IngamePrefabFolder = "Assets/ResWork/Prefabs/Ingame/";
const string PcPrefabFolder = "Assets/Res_Addr/PC/"; const string PcPrefabFolder = "Assets/Res_Addr/PC/";
const string DummyPrefab = "Assets/Res_Addr/Mobs/WL/RPG_Bat.prefab"; const string DummyPrefab = "Assets/Res_Addr/Mobs/WL/RPG_Bat.prefab";
const string NewGameUiPrefab = "Assets/Res_Addr/MainUI/NewGameUI.prefab"; // 원본 HUD — 가상패드(Floating Joystick)·캔버스 스케일을 여기서 읽어 복제한다
public const string NavMeshPath = Folder + "/WLSkillTestNavMesh.asset";
[MenuItem("WL/Skill Test/Build Scene (다시 만들기)")] [MenuItem("WL/Skill Test/Build Scene (다시 만들기)")]
public static void BuildMenu() { Debug.Log(Build()); } public static void BuildMenu() { Debug.Log(Build()); }
@ -75,6 +80,32 @@ namespace WL.SkillTest.Editor
return p; return p;
} }
/// <summary>원본 HUD(NewGameUI)의 가상패드를 그대로 — 캔버스 스케일(원본 1920×1080 Expand)과 Floating Joystick 중첩 프리팹 · RectTransform 값을 원본 프리팹에서 읽어 복제한다
/// (PD 2026-10-20 #947 「원본과 동일한 가상패드 조작 + 키 입력」 · 값을 코드에 적지 않는다 C45).</summary>
static string AddOriginalJoystick(GameObject canvasGo, Scene scene)
{
var hud = AssetDatabase.LoadAssetAtPath<GameObject>(NewGameUiPrefab);
if (hud == null) return "🔴 NewGameUI 프리팹 없음 " + NewGameUiPrefab + "\n";
var srcScaler = hud.GetComponentInChildren<CanvasScaler>(true);
var dstScaler = canvasGo.GetComponent<CanvasScaler>();
if (srcScaler != null && dstScaler != null)
{
dstScaler.uiScaleMode = srcScaler.uiScaleMode; dstScaler.referenceResolution = srcScaler.referenceResolution;
dstScaler.screenMatchMode = srcScaler.screenMatchMode; dstScaler.matchWidthOrHeight = srcScaler.matchWidthOrHeight;
dstScaler.referencePixelsPerUnit = srcScaler.referencePixelsPerUnit;
}
var srcJoy = hud.GetComponentInChildren<FloatingJoystick>(true);
if (srcJoy == null) return "🔴 NewGameUI 안에 FloatingJoystick 없음\n";
var srcPrefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(srcJoy.gameObject); // 중첩 프리팹의 원본(Joystick Pack · Floating Joystick.prefab)
var joy = srcPrefab != null ? PrefabUtility.InstantiatePrefab(srcPrefab, scene) as GameObject : Object.Instantiate(srcJoy.gameObject);
joy.name = srcJoy.gameObject.name;
joy.transform.SetParent(canvasGo.transform, false);
joy.transform.SetAsFirstSibling();
var s = srcJoy.GetComponent<RectTransform>(); var d = joy.GetComponent<RectTransform>();
d.anchorMin = s.anchorMin; d.anchorMax = s.anchorMax; d.pivot = s.pivot; d.sizeDelta = s.sizeDelta; d.anchoredPosition = s.anchoredPosition; d.localScale = s.localScale;
return "";
}
static TextMeshProUGUI MakeLabel(Transform canvas, string name, Vector2 anchor, Vector2 pos, Vector2 size, TextAlignmentOptions align) static TextMeshProUGUI MakeLabel(Transform canvas, string name, Vector2 anchor, Vector2 pos, Vector2 size, TextAlignmentOptions align)
{ {
var go = new GameObject(name, typeof(RectTransform)); var go = new GameObject(name, typeof(RectTransform));
@ -118,6 +149,18 @@ namespace WL.SkillTest.Editor
ground.GetComponent<Renderer>().sharedMaterial = mat; ground.GetComponent<Renderer>().sharedMaterial = mat;
GameObjectUtility.SetStaticEditorFlags(ground, StaticEditorFlags.BatchingStatic); GameObjectUtility.SetStaticEditorFlags(ground, StaticEditorFlags.BatchingStatic);
// NavMesh 사전 베이크 — 런타임 베이크(#947 실측 5.3 s)를 없앤다. 데이터는 씬 옆 에셋 · 하네스는 데이터가 있으면 베이크를 건너뛴다(NavMeshSurface.OnEnable 이 등록)
var surf = ground.AddComponent<NavMeshSurface>();
surf.useGeometry = NavMeshCollectGeometry.PhysicsColliders;
surf.collectObjects = CollectObjects.All;
surf.BuildNavMesh();
if (surf.navMeshData != null)
{
if (AssetDatabase.LoadAssetAtPath<NavMeshData>(NavMeshPath) != null) AssetDatabase.DeleteAsset(NavMeshPath);
AssetDatabase.CreateAsset(surf.navMeshData, NavMeshPath);
}
else sb.Append("🔴 NavMesh 베이크 실패(런타임 베이크로 대체)\n");
var mgr = new GameObject("Mgr"); mgr.AddComponent<AddrResourceMgr>(); mgr.AddComponent<CoroutineMgr>(); mgr.AddComponent<TimeMgr>(); var mgr = new GameObject("Mgr"); mgr.AddComponent<AddrResourceMgr>(); mgr.AddComponent<CoroutineMgr>(); mgr.AddComponent<TimeMgr>();
var es = new GameObject("EventSystem"); es.AddComponent<EventSystem>(); es.AddComponent<StandaloneInputModule>(); var es = new GameObject("EventSystem"); es.AddComponent<EventSystem>(); es.AddComponent<StandaloneInputModule>();
// InGame.unity 의 씬 객체(직렬화 참조 0 · 몬스터 웨이브 스탯 표) — 원본 ActorStatInfo.Reset 이 DungeonInfo.Ins.dic_WaveStat 를 읽어 없으면 PC.Set 이 NRE(#947 1차 Play 실측) // InGame.unity 의 씬 객체(직렬화 참조 0 · 몬스터 웨이브 스탯 표) — 원본 ActorStatInfo.Reset 이 DungeonInfo.Ins.dic_WaveStat 를 읽어 없으면 PC.Set 이 NRE(#947 1차 Play 실측)
@ -161,6 +204,8 @@ namespace WL.SkillTest.Editor
labels[1] = MakeLabel(canvasGo.transform, "mobstat", new Vector2(1f, 0f), new Vector2(-10f, 10f), new Vector2(360f, 220f), TextAlignmentOptions.BottomRight); labels[1] = MakeLabel(canvasGo.transform, "mobstat", new Vector2(1f, 0f), new Vector2(-10f, 10f), new Vector2(360f, 220f), TextAlignmentOptions.BottomRight);
labels[2] = MakeLabel(canvasGo.transform, "dmg", new Vector2(1f, 1f), new Vector2(-10f, -10f), new Vector2(420f, 300f), TextAlignmentOptions.TopRight); labels[2] = MakeLabel(canvasGo.transform, "dmg", new Vector2(1f, 1f), new Vector2(-10f, -10f), new Vector2(420f, 300f), TextAlignmentOptions.TopRight);
labels[3] = MakeLabel(canvasGo.transform, "classinfo", new Vector2(0.5f, 0f), new Vector2(0f, 10f), new Vector2(600f, 40f), TextAlignmentOptions.Bottom); labels[3] = MakeLabel(canvasGo.transform, "classinfo", new Vector2(0.5f, 0f), new Vector2(0f, 10f), new Vector2(600f, 40f), TextAlignmentOptions.Bottom);
foreach (var l in labels) l.raycastTarget = false; // 글자가 가상패드 터치를 가리지 않게
sb.Append(AddOriginalJoystick(canvasGo, scene));
var hGo = new GameObject("WLSkillTestHarness"); var hGo = new GameObject("WLSkillTestHarness");
var h = hGo.AddComponent<WLSkillTestHarness>(); var h = hGo.AddComponent<WLSkillTestHarness>();

View File

@ -7,6 +7,7 @@
"dummyMobId": 0, "dummyMobId": 0,
"dummyOffset": [0, 0, 0], "dummyOffset": [0, 0, 0],
"dummyStill": 1, "dummyStill": 1,
"preloadEffects": 0,
"moveKeys": 1, "moveKeys": 1,
"attackKey": "Space", "attackKey": "Space",
"weaponPrevKey": "O", "weaponPrevKey": "O",

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,8 @@
// ■ 원본 코드와의 접점 = StatTest 전용 분기 13곳을 `WLTestScene.Active`(StatTest 또는 WLSkillTest)로 넓힌 것뿐(HUD·포털·서버 일시정지·대상 목록 분기 · 전부 #if UNITY_EDITOR 안). // ■ 원본 코드와의 접점 = StatTest 전용 분기 13곳을 `WLTestScene.Active`(StatTest 또는 WLSkillTest)로 넓힌 것뿐(HUD·포털·서버 일시정지·대상 목록 분기 · 전부 #if UNITY_EDITOR 안).
// 이동·넉백·소환 AI 분기(Actor 1665·1710·2198 · MobActor 75 · SummonActor 60 · WizardActor 53·61)는 StatTest 전용으로 남겨 **실제 게임 동작**을 유지한다. // 이동·넉백·소환 AI 분기(Actor 1665·1710·2198 · MobActor 75 · SummonActor 60 · WizardActor 53·61)는 StatTest 전용으로 남겨 **실제 게임 동작**을 유지한다.
// ■ 이 클래스가 MainToStatTest 를 상속하는 이유 = 원본 분기가 `MainToStatTest.Ins.actors[1]`(대상)·`Set_Dmglabel`(피해 글자)를 부른다 → 같은 자리를 채워 준다. // ■ 이 클래스가 MainToStatTest 를 상속하는 이유 = 원본 분기가 `MainToStatTest.Ins.actors[1]`(대상)·`Set_Dmglabel`(피해 글자)를 부른다 → 같은 자리를 채워 준다.
// ■ 키: WASD/방향키 이동(섬 조이스틱과 같은 호출 · Set_AutoBraking(false) → JoystickStatus 1 → Run_byJoystick) · Space 기본 공격 1타 · Q 주력 · E 각성 · 숫자 등급(기존 훅) // ■ 조작: **원본 가상패드**(NewGameUI 의 Floating Joystick 중첩 프리팹을 빌더가 같은 값으로 복제 · 화면 왼쪽 드래그 · PD 2026-10-20 #947 「원본과 동일한 가상패드 + 키 입력」)
// + WASD/방향키 이동(같은 호출 · Set_AutoBraking(false) → JoystickStatus 1 → Run_byJoystick) · Space 기본 공격 1타 · Q 주력 · E 각성 · 숫자 등급(기존 훅)
// · O 무기 이전(왼쪽 순환) · P 무기 다음(오른쪽 순환) — PD 2026-10-20 #947 지시 · 종류(GroupNo)마다 1개 · R 더미 제자리 · T 슬로 모션 · Pause = 설정값(기본 Backslash) // · O 무기 이전(왼쪽 순환) · P 무기 다음(오른쪽 순환) — PD 2026-10-20 #947 지시 · 종류(GroupNo)마다 1개 · R 더미 제자리 · T 슬로 모션 · Pause = 설정값(기본 Backslash)
// ■ 값 = Resources/WL/WLSkillTest.json (C45) · 상태 파일 = Library/WLSkillTest_status.txt(외부 스크립트는 Play 중 eval 대신 이 파일) · 🔴 Debug.LogError 금지(원본 ErrorLogHook 팝업) // ■ 값 = Resources/WL/WLSkillTest.json (C45) · 상태 파일 = Library/WLSkillTest_status.txt(외부 스크립트는 Play 중 eval 대신 이 파일) · 🔴 Debug.LogError 금지(원본 ErrorLogHook 팝업)
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────
@ -31,6 +32,8 @@ namespace WL.SkillTest
{ {
public const string Name = "WLSkillTest"; public const string Name = "WLSkillTest";
public static bool Active { get { var n = SceneManager.GetActiveScene().name; return n == Name || n == "StatTest"; } } public static bool Active { get { var n = SceneManager.GetActiveScene().name; return n == Name || n == "StatTest"; } }
/// <summary>테스트 씬에서 원본 InGameInfo.Start 의 이펙트·스킬 예열(인스턴스 514 · 한 프레임 18 s · #947 실측)을 돌릴지 — JSON preloadEffects(기본 0 = 생략 · 첫 사용 때 로드).</summary>
public static bool PreloadEffects { get { return WLSkillTestHarness.Cfg.preloadEffects != 0; } }
} }
[System.Serializable] [System.Serializable]
@ -44,7 +47,8 @@ namespace WL.SkillTest
public int dummyMobId = 0; // 0 = WLIslandMobSettings.hitTestDummyMobId (몬스터 표 행 · 능력치) public int dummyMobId = 0; // 0 = WLIslandMobSettings.hitTestDummyMobId (몬스터 표 행 · 능력치)
public float[] dummyOffset = { 0f, 0f, 0f }; // 전부 0 = WLIslandMobSettings.hitTestDummyOffset public float[] dummyOffset = { 0f, 0f, 0f }; // 전부 0 = WLIslandMobSettings.hitTestDummyOffset
public int dummyStill = 1; // 1 = 더미 제자리 public int dummyStill = 1; // 1 = 더미 제자리
public int moveKeys = 1; public int preloadEffects = 0; // 1 = 원본 InGameInfo 이펙트·스킬 예열(514 인스턴스 · 약 18 s) · 0 = 생략(첫 사용 때 로드)
public int moveKeys = 1; // 1 = WASD/방향키도 이동(가상패드와 함께 · PD #947 「가상패드 + 키 입력」)
public string attackKey = "Space"; public string attackKey = "Space";
public string weaponPrevKey = "O"; // PD #947: O = 무기 왼쪽 순환 public string weaponPrevKey = "O"; // PD #947: O = 무기 왼쪽 순환
public string weaponNextKey = "P"; // PD #947: P = 무기 오른쪽 순환 public string weaponNextKey = "P"; // PD #947: P = 무기 오른쪽 순환
@ -126,8 +130,8 @@ namespace WL.SkillTest
while (TableChecker.Ins == null || !TableChecker.Ins.CheckAllLoad()) yield return null; while (TableChecker.Ins == null || !TableChecker.Ins.CheckAllLoad()) yield return null;
Lap("tables"); Lap("tables");
// InGameInfo.Start 의 이펙트 예열 루프(테이블 0.1 s 폴링 뒤 1프레임)가 끝난 다음에 PC 를 만든다 — 먼저 만들면 PC 피격 이펙트 키가 먼저 등록돼 그 루프의 Add 가 ArgumentException 으로 끊긴다(#947 2차 Play 실측) // 예열을 켠 경우만: InGameInfo.Start 의 이펙트 예열 루프(테이블 0.1 s 폴링 뒤 1프레임)가 끝난 다음에 PC 를 만든다(먼저 만들면 PC 피격 이펙트 키가 먼저 등록돼 그 루프의 Add 가 중복 · #947 2차 Play 실측 · 원본에 가드도 넣음)
for (float t = 0f; t < 3f && !EffectsPreloaded(); t += Time.unscaledDeltaTime) yield return null; if (cfg.preloadEffects != 0) for (float t = 0f; t < 3f && !EffectsPreloaded(); t += Time.unscaledDeltaTime) yield return null;
Lap("ingameinfo"); Lap("ingameinfo");
if (pcActor == null || dummyActor == null) { Fail("refs-missing", "pcActor/dummyActor 참조 없음 — Build Scene 다시"); yield break; } if (pcActor == null || dummyActor == null) { Fail("refs-missing", "pcActor/dummyActor 참조 없음 — Build Scene 다시"); yield break; }
@ -232,6 +236,30 @@ namespace WL.SkillTest
return "이동 시작 " + seconds + " s (h " + h + " · v " + v + ")"; return "이동 시작 " + seconds + " s (h " + h + " · v " + v + ")";
} }
/// <summary>검증용 — 원본 가상패드(FloatingJoystick)를 화면 왼쪽 아래에서 누르고 (dx, dy) 방향으로 끈 채 seconds 유지한 뒤 뗀다(실제 터치와 같은 OnPointerDown → OnDrag → OnPointerUp). 결과 = MoveLog.</summary>
public static string PadFor(float seconds, float dx, float dy)
{
var ins = Ins as WLSkillTestHarness; if (ins == null) return "하네스 없음";
if (!Ready || MyValue.MyPC == null) return "ready 아님";
MoveLog = "패드 이동 중"; ins.StartCoroutine(ins.CoPad(seconds, dx, dy));
return "패드 시작 " + seconds + " s (" + dx + ", " + dy + ")";
}
IEnumerator CoPad(float seconds, float dx, float dy)
{
var joy = Object.FindAnyObjectByType<FloatingJoystick>(); var pc = MyValue.MyPC as PCActor;
if (joy == null || pc == null) { MoveLog = joy == null ? "FloatingJoystick 없음" : "PC 없음"; yield break; }
var ev = new UnityEngine.EventSystems.PointerEventData(UnityEngine.EventSystems.EventSystem.current);
Vector2 p0 = new Vector2(Screen.width * 0.25f, Screen.height * 0.3f), dir = new Vector2(dx, dy).normalized;
ev.position = p0; joy.OnPointerDown(ev);
Vector3 w0 = pc.Get_position(); float t0 = Time.time; string animMid = "-";
while (Time.time - t0 < seconds) { ev.position = p0 + dir * (Screen.height * 0.12f); joy.OnDrag(ev); animMid = pc.Get_CurAnim().ToString(); yield return null; }
string padDir = joy.Direction.ToString("F2");
joy.OnPointerUp(ev);
yield return null;
MoveLog = "패드 이동 " + Vector3.Distance(w0, pc.Get_position()).ToString("F2") + " m / " + seconds + " s · 패드 입력 " + padDir + " · 이동 중 anim " + animMid + " → 뗀 뒤 " + pc.Get_CurAnim() + " · joystick " + pc.JoystickStatus + " · RealCamera " + (MyValue.m_RealCamera != null);
}
IEnumerator CoMove(float seconds, float h, float v) IEnumerator CoMove(float seconds, float h, float v)
{ {
var pc = MyValue.MyPC as PCActor; if (pc == null) yield break; var pc = MyValue.MyPC as PCActor; if (pc == null) yield break;
@ -249,6 +277,7 @@ namespace WL.SkillTest
{ {
try try
{ {
WLWeaponClasses.Ensure(); // WL 추가 직업(대검 10801 등)을 ClassConfig 사전에 먼저 — 섬은 PCActor.Set 의 ResolveSpawnClass 훅이 하지만 이 씬의 ServerData 는 새 것이라 그 훅을 타지 않는다(#947 2회차 Play 실측: 대검 낀 세이브로 시작 → KeyNotFound 10801)
if (WLInventory.EnsureLoaded()) if (WLInventory.EnsureLoaded())
{ {
var w = WLInventory.EquippedInSlot(eFREquipmentType.Weapon); var w = WLInventory.EquippedInSlot(eFREquipmentType.Weapon);
@ -284,6 +313,7 @@ namespace WL.SkillTest
void BakeGround() void BakeGround()
{ {
var surf = Object.FindFirstObjectByType<NavMeshSurface>(); var surf = Object.FindFirstObjectByType<NavMeshSurface>();
if (surf != null && surf.navMeshData != null) return; // 빌더가 구워 둔 데이터(씬 옆 에셋 · OnEnable 이 등록) — 런타임 베이크 5 s 생략
if (surf == null) { var ground = GameObject.Find("Ground"); if (ground == null) return; surf = ground.AddComponent<NavMeshSurface>(); } if (surf == null) { var ground = GameObject.Find("Ground"); if (ground == null) return; surf = ground.AddComponent<NavMeshSurface>(); }
surf.useGeometry = UnityEngine.AI.NavMeshCollectGeometry.PhysicsColliders; surf.useGeometry = UnityEngine.AI.NavMeshCollectGeometry.PhysicsColliders;
surf.BuildNavMesh(); surf.BuildNavMesh();
@ -388,7 +418,7 @@ namespace WL.SkillTest
if (WLInventory.Loaded) { var cur = WLInventory.EquippedInSlot(eFREquipmentType.Weapon); if (cur != null && cur.itemJson != null) w = cur.itemJson.Item_name + "(" + cur.itemJson.GroupNo + ")"; } if (WLInventory.Loaded) { var cur = WLInventory.EquippedInSlot(eFREquipmentType.Weapon); if (cur != null && cur.itemJson != null) w = cur.itemJson.Item_name + "(" + cur.itemJson.GroupNo + ")"; }
string s = "WL 스킬 테스트 · " + Stage + (Ready ? "" : " …") + string s = "WL 스킬 테스트 · " + Stage + (Ready ? "" : " …") +
"\n무기 " + w + " 더미 HP " + (Dummy != null ? Dummy.Get_HP().ToString("F0") : "-") + (_slow ? " [슬로 ×" + Time.timeScale + "]" : "") + "\n무기 " + w + " 더미 HP " + (Dummy != null ? Dummy.Get_HP().ToString("F0") : "-") + (_slow ? " [슬로 ×" + Time.timeScale + "]" : "") +
"\nWASD 이동 · " + _kAttack + " 공격 · " + WLSkillHotkey.Key + " 주력 · " + (WLSkillHotkey.Key2 != KeyCode.None ? WLSkillHotkey.Key2 + " 각성 · " : "") + "숫자 등급 · " + "\n가상패드(왼쪽 화면 드래그 · 원본과 동일) 또는 WASD 이동 · " + _kAttack + " 공격 · " + WLSkillHotkey.Key + " 주력 · " + (WLSkillHotkey.Key2 != KeyCode.None ? WLSkillHotkey.Key2 + " 각성 · " : "") + "숫자 등급 · " +
_kPrev + " 무기 이전 · " + _kNext + " 무기 다음 · " + _kReset + " 더미 · " + _kSlow + " 슬로 · " + _kPause + " 일시정지" + _kPrev + " 무기 이전 · " + _kNext + " 무기 다음 · " + _kReset + " 더미 · " + _kSlow + " 슬로 · " + _kPause + " 일시정지" +
(string.IsNullOrEmpty(_msg) ? "" : "\n" + _msg) + (Ready ? "\n" + string.Join(" · ", Laps.ToArray()) : ""); (string.IsNullOrEmpty(_msg) ? "" : "\n" + _msg) + (Ready ? "\n" + string.Join(" · ", Laps.ToArray()) : "");
var r = new Rect(Screen.width * 0.01f, Screen.height * 0.01f, Screen.width * 0.6f, Screen.height * 0.3f); var r = new Rect(Screen.width * 0.01f, Screen.height * 0.01f, Screen.width * 0.6f, Screen.height * 0.3f);

Binary file not shown.

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 118c1cf39773525428ab565351200b2b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 23800000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -25,7 +25,7 @@ EditorSettings:
m_AsyncShaderCompilation: 1 m_AsyncShaderCompilation: 1
m_PrefabModeAllowAutoSave: 1 m_PrefabModeAllowAutoSave: 1
m_EnterPlayModeOptionsEnabled: 1 m_EnterPlayModeOptionsEnabled: 1
m_EnterPlayModeOptions: 0 m_EnterPlayModeOptions: 3
m_GameObjectNamingDigits: 1 m_GameObjectNamingDigits: 1
m_GameObjectNamingScheme: 0 m_GameObjectNamingScheme: 0
m_AssetNamingUsesSpace: 1 m_AssetNamingUsesSpace: 1