From 6cb9f40944a19ea036bb21b619b51500ddf73ed8 Mon Sep 17 00:00:00 2001 From: swrring Date: Sun, 13 Sep 2026 18:06:38 +0900 Subject: [PATCH] =?UTF-8?q?[WL-816i2]=20=EB=8D=98=EC=A0=84=20=EC=9E=AC?= =?UTF-8?q?=EC=9E=85=EC=9E=A5=20=EC=8B=9C=20=EC=A0=84=ED=88=AC=EA=B0=80=20?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8D=98=20?= =?UTF-8?q?=EA=B2=83=20=EC=88=98=EC=A0=95=20(#816)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 원인(실측): 전투 시작 신호는 RealCamera 의 카메라 연출이 끝날 때 나온다 — PCActor.StartCam → Set_Target(pc, CamRot_Portal) → CamStatus=0 + list_tfCamactionTarget.Add(pc) → LateUpdate 가 목록을 다 비우면 Start_Game() → ActorInfo.All_Stop(false) + DungeonInfo.Start_Dungeon. 그런데 원본에 그 목록을 비우는 곳이 없어 맵을 바꾸면 **죽은 Transform** 이 남고, 재입장 때 `camTarget.position`(RealCamera.cs:199)이 MissingReferenceException 을 던져 LateUpdate 가 매 프레임 끊긴다 → Start_Game() 이 영영 안 불려 전투가 멈춘 채로 남는다. (816i 가 Get_PortalPos 콜백을 되살리기 전에는 이 경로 자체가 안 돌아 드러나지 않았다.) → 죽은 항목만 걷어내고, 비면 지금 대상을 한 개 채운다(원본 0줄 · SO 로 끔). - 같은 씬을 쓰는 던전(1·3 = WL_Dungeon01, 2·4 = WL_Dungeon02)에서 씬 이름으로만 찾느라 **언제나 앞 줄**의 스테이지가 돌던 것 수정 — 입장 요청(Pending)을 우선한다. 실측: 던전 3 입장 시 stageIndex 12·보상 192(전에는 10·96). - 던전 전용 카메라 거리(dungeonCamDistance)를 SO 에 분리(섬 값은 그대로). Co-Authored-By: Claude Opus 5 --- .../Resources/WL/WLIslandSettings.asset | 2 + Assets/WL/Island/WLIslandBridge.cs | 13 +++- Assets/WL/Island/WLIslandCameraRig.cs | 60 ++++++++++++++++++- Assets/WL/Island/WLIslandSettings.cs | 14 ++++- 4 files changed, 85 insertions(+), 4 deletions(-) diff --git a/Assets/WL/Island/Resources/WL/WLIslandSettings.asset b/Assets/WL/Island/Resources/WL/WLIslandSettings.asset index f77790e6c..f73ded1a9 100644 --- a/Assets/WL/Island/Resources/WL/WLIslandSettings.asset +++ b/Assets/WL/Island/Resources/WL/WLIslandSettings.asset @@ -82,12 +82,14 @@ MonoBehaviour: camPitch: 45 camYaw: 0 camDistance: 22 + dungeonCamDistance: 18 camFov: 60 camLookHeight: 0 camLockYaw: 1 camLeadMultiplier: 1 fixDegenerateCameras: 1 cameraGuardInterval: 0.5 + fixCamActionTargets: 1 dungeons: - enabled_: 1 id: 1 diff --git a/Assets/WL/Island/WLIslandBridge.cs b/Assets/WL/Island/WLIslandBridge.cs index efd871b9d..14631f09d 100644 --- a/Assets/WL/Island/WLIslandBridge.cs +++ b/Assets/WL/Island/WLIslandBridge.cs @@ -111,7 +111,13 @@ namespace WL.Island return; } - var dg = cfg.FindBySceneName(scene.name); + // 🔴 WL-816i2 — 들어가겠다고 **요청한** 던전이 우선이다. + // 표에서 씬 이름으로만 찾으면(FindBySceneName) 같은 씬을 쓰는 던전 1·3(WL_Dungeon01), + // 2·4(WL_Dungeon02) 중 **언제나 앞 줄**이 잡혀, 던전 3 에 들어가도 던전 1 의 스테이지 + // (몹 3마리 · 보상 배수 1)가 돌았다. 그래서 「다른 던전에 들어가도 전투가 이상하다」가 된다. + var dg = WLDungeonSceneSetup.Pending; + if (dg == null || dg.enabled_ == 0 || !scene.name.Equals(dg.sceneName)) + dg = cfg.FindBySceneName(scene.name); if (dg != null) { DungeonLoads++; @@ -388,6 +394,11 @@ namespace WL.Island if (cfg == null || cfg.enabled_ == 0) return; WLDungeonGate.TickAll(cfg); + // 🔴 WL-816i2 — 재입장 시 전투가 시작되지 않던 것: 죽은 카메라 연출 대상을 걷어낸다. + // 매 프레임 · 목록이 비었거나 죽은 항목이 없으면 아무 일도 하지 않는다(근거는 WLIslandCameraRig.cs). + if (cfg.fixCamActionTargets != 0) + WLDungeonCameraRig.PruneCamActionTargets(MyValue._RealCamera); + // WL-816i 에러 ② — 투영이 깨진 카메라 감시(자세한 근거는 WLIslandCameraRig.cs) if (cfg.fixDegenerateCameras == 0) return; _guardTimer -= Time.unscaledDeltaTime; diff --git a/Assets/WL/Island/WLIslandCameraRig.cs b/Assets/WL/Island/WLIslandCameraRig.cs index a815d9fbc..f7728c666 100644 --- a/Assets/WL/Island/WLIslandCameraRig.cs +++ b/Assets/WL/Island/WLIslandCameraRig.cs @@ -86,6 +86,20 @@ namespace WL.Island return true; } + /// + /// 던전에서 쓸 카메라 거리(m). WL-816i2 — PD 「던전에서는 카메라를 조금만 더 당기자」. + /// 각도·yaw·FOV 는 섬 그대로 두고 **거리만** 던전 전용 값을 쓴다. 0 이하면 섬 값을 그대로 쓴다. + /// + public static float DungeonDistance(WLIslandSettings cfg) + { + if (cfg == null) return 22f; + if (DistanceOverride > 0f) return DistanceOverride; // 검증용(프로브) + return cfg.dungeonCamDistance > 0f ? cfg.dungeonCamDistance : cfg.camDistance; + } + + /// 검증 전용 — 0 보다 크면 그 거리를 쓴다(3단 비교 캡처용 · 실기에는 영향 0). + public static float DistanceOverride = 0f; + /// 스테이지 진입 시 원본이 쓰는 초기 카메라 방향(MapZoneData.CamRot_Portal) 값. public static float SolvedYaw(WLIslandSettings cfg) { @@ -112,8 +126,9 @@ namespace WL.Island Save(); } + float dist = DungeonDistance(_cfg); // WL-816i2 — 던전만 조금 더 당긴다(각도·FOV 는 섬 그대로) float camHeight, away, up, rot; - if (!Solve(_cfg.camPitch, _cfg.camDistance, _cfg.camYaw, out camHeight, out away, out up, out rot)) return; + if (!Solve(_cfg.camPitch, dist, _cfg.camYaw, out camHeight, out away, out up, out rot)) return; _rc.cameraHeight = camHeight; _rc.minDistance = away; @@ -148,7 +163,7 @@ namespace WL.Island } Applies++; - LastApplied = "pitch " + camHeight.ToString("F2") + "° · 거리 " + _cfg.camDistance.ToString("F2") + + LastApplied = "pitch " + camHeight.ToString("F2") + "° · 거리 " + dist.ToString("F2") + " m · FOV " + _cfg.camFov.ToString("F1") + " · (RealCamera away " + away.ToString("F4") + " · up " + up.ToString("F4") + " · rotateAround " + rot.ToString("F3") + ")"; } @@ -211,6 +226,47 @@ namespace WL.Island public static int Repairs; public static string LastRepair = ""; + // ───────────────────────────────────────────────────────────────── + // WL-816i2 — 「재입장하면 전투가 진행되지 않는다」(PD) 의 원인 지점 + // + // 원본 흐름(실측): 전투는 이렇게 **시작**된다. + // InGameInfo.StartCam → PCActor.StartCam(PCActor.cs:245) + // → LoadMapMgr.Get_PortalPos 콜백 → RealCamera.Set_Target(pc, CamRot_Portal) + // → CamStatus = 0 · list_tfCamactionTarget.Add(pc) (RealCamera.cs:84·87) + // → LateUpdate 의 CamStatus==0 가지가 목록을 **다 비우면** Start_Game() (RealCamera.cs:212) + // → ActorInfo.All_Stop(false) + Time.timeScale + DungeonInfo.Start_Dungeon(true) + // 🔴 `list_tfCamactionTarget` 은 원본에 **비우는 곳이 없다**(Add 와 RemoveAt(0) 뿐 · RealCamera.cs:52·122). + // 맵을 바꾸면 그 목록의 Transform(이전 맵 PC)은 파괴되는데 항목은 남는다. + // 그 상태로 다시 입장하면 CamStatus==0 가지의 첫 줄 `camTarget.position`(RealCamera.cs:197·199)이 + // **MissingReferenceException** 을 던져 LateUpdate 가 매 프레임 중단된다 → + // 목록이 영영 안 비고 → **Start_Game() 이 안 불려 전투가 멈춘 채로 남는다.** + // → 원본 0줄 유지를 위해 **죽은 항목만 걷어낸다**. 다 걷어내 비면 지금 대상을 한 개 넣어 + // 원본이 정상적으로 목록을 소진하고 Start_Game() 에 도달하게 한다(= 첫 입장과 같은 경로). + // ───────────────────────────────────────────────────────────────── + public static int CamTargetsPruned, CamTargetsRefilled; + + static readonly System.Reflection.FieldInfo F_CamActionList = + typeof(RealCamera).GetField("list_tfCamactionTarget", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + + /// 죽은 카메라 연출 대상만 걷어낸다. 걷어낸 개수를 돌려준다(정상이면 0 · 아무것도 안 한다). + public static int PruneCamActionTargets(RealCamera rc) + { + if (rc == null || F_CamActionList == null) return 0; + var list = F_CamActionList.GetValue(rc) as System.Collections.Generic.List; + if (list == null || list.Count == 0) return 0; + + int removed = 0; + for (int i = list.Count - 1; i >= 0; i--) + if (list[i] == null) { list.RemoveAt(i); removed++; } + if (removed == 0) return 0; + + CamTargetsPruned += removed; + // 🔴 다 걷어내 비었는데 CamStatus 가 0 이면 원본이 list[0] 에서 터진다 → 지금 대상을 한 개 채워 준다. + if (list.Count == 0 && rc.target != null) { list.Add(rc.target); CamTargetsRefilled++; } + return removed; + } + /// 투영이 깨진 카메라를 찾아 되살린다. 되살린 수를 돌려준다(정상이면 0 · 로그도 없다). public static int RepairDegenerateCameras(WLIslandSettings cfg) { diff --git a/Assets/WL/Island/WLIslandSettings.cs b/Assets/WL/Island/WLIslandSettings.cs index c7c9c1f47..ce4655aa7 100644 --- a/Assets/WL/Island/WLIslandSettings.cs +++ b/Assets/WL/Island/WLIslandSettings.cs @@ -328,9 +328,15 @@ namespace WL.Island [Tooltip("섬 카메라 수평 방향(도). 섬은 플레이어를 따라 돌지 않는 고정 구도라 0.")] public float camYaw = 0f; - [Tooltip("섬 카메라와 대상 사이 거리(m). 섬 실측 = 22 (CinemachineFramingTransposer.m_CameraDistance).")] + [Tooltip("섬 카메라와 대상 사이 거리(m). 섬 실측 = 22 (CinemachineFramingTransposer.m_CameraDistance). " + + "🔴 섬은 이 값을 쓰지 않는다(FI Cinemachine 이 스스로 잡는다) — 기준 기록용이자 아래 던전 값의 기본값이다.")] public float camDistance = 22f; + [Tooltip("🔴 **던전 전용** 카메라 거리(m) — WL-816i2 · PD 「던전에서는 카메라를 조금만 더 당기자」. " + + "0 이하면 위 섬 값(22)을 그대로 쓴다. 각도 45°·yaw 0°·FOV 60 은 섬과 같게 유지하고 **거리만** 줄인다. " + + "섬은 이 값에 전혀 영향받지 않는다.")] + public float dungeonCamDistance = 18f; + [Tooltip("섬 카메라 화각(도). 섬 실측 = 60 · 원근 투영.")] public float camFov = 60f; @@ -354,6 +360,12 @@ namespace WL.Island [Tooltip("위 감시 주기(초).")] public float cameraGuardInterval = 0.5f; + [Tooltip("1 이면 `RealCamera.list_tfCamactionTarget` 에 남은 **죽은 연출 대상**을 걷어낸다(WL-816i2). " + + "이게 남아 있으면 재입장 때 RealCamera.LateUpdate 가 매 프레임 예외로 끊겨 " + + "`Start_Game()`(= ActorInfo.All_Stop(false) · DungeonInfo.Start_Dungeon)이 불리지 않아 **전투가 시작되지 않는다**. " + + "0 이면 무동작(= 816i 까지의 동작).")] + public int fixCamActionTargets = 1; + // ───────────────────────────────── 던전 표 [Header("던전 표 — 한 줄 = 던전 하나")] public WLDungeonDef[] dungeons = new WLDungeonDef[0];