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];