From d1ba5d5c18a5a7dc0c50bbe47281860054070d5bd2e0e9c2afd3953b38d5b151 Mon Sep 17 00:00:00 2001 From: copecone Date: Mon, 19 Oct 2026 18:14:02 +0900 Subject: [PATCH] Add Disable Tile Culling Option --- Core/RenderManager.cs | 8 +++++++ Data/RenderConfig.cs | 7 +++++++ Localization/Locale/en.json | 1 + Localization/Locale/ko.json | 1 + Patch/Game/scnGamePatch.cs | 15 +++++++++++-- Patch/Game/scrFloorPatch.cs | 37 +++++++++++++++++++++++++++++++++ UI/Window/RenderConfigWindow.cs | 19 +++++++++++++++++ 7 files changed, 86 insertions(+), 2 deletions(-) diff --git a/Core/RenderManager.cs b/Core/RenderManager.cs index 43ced1e..30a7b15 100644 --- a/Core/RenderManager.cs +++ b/Core/RenderManager.cs @@ -940,6 +940,14 @@ internal class RenderManager : MonoBehaviour // Cancelled or failed during the countdown: do not start the encoder if (stage != RenderStage.OnScene) yield break; + if (Configuration.AdvancedConfig.DisableTileCulling && scrLevelMaker.instance) + { + foreach (var floor in scrLevelMaker.instance.listFloors) + { + if (floor) floor.enabled = true; + } + } + frameCount = 0; framesSent = 0; _renderStopwatch.Restart(); diff --git a/Data/RenderConfig.cs b/Data/RenderConfig.cs index 984543e..4830535 100644 --- a/Data/RenderConfig.cs +++ b/Data/RenderConfig.cs @@ -109,6 +109,12 @@ public class AdvancedConfig /// public bool FixCustomFrameRate { get; set; } = true; + /// + /// When true, prevents floor tiles from being disabled when outside the camera frustum (scrFloor.OnBecameInvisible), + /// eliminating the 1-frame update lag/glitch when tiles enter the screen. Default true. + /// + public bool DisableTileCulling { get; set; } = true; + /// File extension of the default output file name, without the dot (e.g. "mkv", "mp4"); selects the container. public string FileExtension { get; set; } = "mkv"; @@ -136,6 +142,7 @@ public class AdvancedConfig NonTile = source.NonTile; HighResBloomCorrection = source.HighResBloomCorrection; FixCustomFrameRate = source.FixCustomFrameRate; + DisableTileCulling = source.DisableTileCulling; FileExtension = source.FileExtension; firePlanetColor = source.firePlanetColor; icePlanetColor = source.icePlanetColor; diff --git a/Localization/Locale/en.json b/Localization/Locale/en.json index 4540cd9..218a31a 100644 --- a/Localization/Locale/en.json +++ b/Localization/Locale/en.json @@ -44,6 +44,7 @@ "ui.render_config.non_tile": "Non-Tile Mode", "ui.render_config.high_res_bloom_correction": "High-Resolution Bloom Correction", "ui.render_config.fix_custom_frame_rate": "Fix Custom FPS Render Timing", + "ui.render_config.disable_tile_culling": "Disable Tile Culling", "ui.render_config.random_seed": "Random Seed (Optional)", "ui.render_config.validation_title": "Invalid Settings", "ui.render_config.validation_error": "Please check your input values:\n- Width and Height must be integers > 0\n- Render FPS and Video FPS must be > 0\n- Delay After End must be >= 0", diff --git a/Localization/Locale/ko.json b/Localization/Locale/ko.json index 6412a89..dde6e4f 100644 --- a/Localization/Locale/ko.json +++ b/Localization/Locale/ko.json @@ -44,6 +44,7 @@ "ui.render_config.non_tile": "논타일 모드", "ui.render_config.high_res_bloom_correction": "고해상도 블룸 보정", "ui.render_config.fix_custom_frame_rate": "커스텀 FPS 렌더 타이밍 보정", + "ui.render_config.disable_tile_culling": "타일 컬링 비활성화", "ui.render_config.random_seed": "랜덤 시드 (선택 사항)", "ui.render_config.validation_title": "설정 오류", "ui.render_config.validation_error": "입력값을 확인해 주세요:\n- 너비와 높이는 0보다 큰 정수여야 합니다.\n- 렌더 FPS와 영상 FPS는 0보다 커야 합니다.\n- 종료 후 대기 시간은 0 이상이어야 합니다.", diff --git a/Patch/Game/scnGamePatch.cs b/Patch/Game/scnGamePatch.cs index 5861eb8..dafd347 100644 --- a/Patch/Game/scnGamePatch.cs +++ b/Patch/Game/scnGamePatch.cs @@ -30,8 +30,19 @@ public static class scnGamePatch [HarmonyPatch("Play")] public static void ProcessFloors() { - var nonTile = RenderManager.Instance.stage >= RenderStage.Load && - RenderManager.Instance.Configuration.AdvancedConfig.NonTile; + if (RenderManager.Instance && + RenderManager.Instance.stage >= RenderStage.Load && + RenderManager.Instance.Configuration?.AdvancedConfig?.DisableTileCulling == true) + { + foreach (var floor in scrLevelMaker.instance.listFloors) + { + if (floor) floor.enabled = true; + } + } + + var nonTile = RenderManager.Instance && + RenderManager.Instance.stage >= RenderStage.Load && + RenderManager.Instance.Configuration?.AdvancedConfig?.NonTile == true; if (!nonTile) return; foreach (var floor in scrLevelMaker.instance.listFloors) diff --git a/Patch/Game/scrFloorPatch.cs b/Patch/Game/scrFloorPatch.cs index c95e26c..69e7d9d 100644 --- a/Patch/Game/scrFloorPatch.cs +++ b/Patch/Game/scrFloorPatch.cs @@ -33,4 +33,41 @@ public class scrFloorPatch RenderManager.Instance.Configuration.AdvancedConfig.NonTile; return !nonTile; } + + /// + /// Postfix of scrFloor.Start. + /// The game sets enabled = isVisible in Start(), which disables all off-screen tiles right at spawn. + /// When DisableTileCulling is enabled, force every floor to remain enabled. + /// + [HarmonyPostfix] + [HarmonyPatch("Start")] + public static void ForceEnableOnStart(scrFloor __instance) + { + if (RenderManager.Instance && + RenderManager.Instance.stage >= RenderStage.Load && + RenderManager.Instance.Configuration.AdvancedConfig.DisableTileCulling) + { + __instance.enabled = true; + } + } + + /// + /// Prefix of scrFloor.OnBecameInvisible. + /// Skips disabling the floor component (enabled = false) while rendering with + /// AdvancedConfig.DisableTileCulling enabled, preventing the 1-frame update lag/glitch + /// when tiles enter the camera view. + /// + [HarmonyPrefix] + [HarmonyPatch("OnBecameInvisible")] + // ReSharper disable once InconsistentNaming + public static bool PreventTileCulling(scrFloor __instance) + { + if (RenderManager.Instance && + RenderManager.Instance.stage >= RenderStage.Load && + RenderManager.Instance.Configuration.AdvancedConfig.DisableTileCulling) + { + return false; + } + return true; + } } \ No newline at end of file diff --git a/UI/Window/RenderConfigWindow.cs b/UI/Window/RenderConfigWindow.cs index e73df77..4aae461 100644 --- a/UI/Window/RenderConfigWindow.cs +++ b/UI/Window/RenderConfigWindow.cs @@ -141,6 +141,7 @@ internal static class RenderConfigWindow private static O5Toggle? _nonTileToggle; private static O5Toggle? _highResBloomCorrectionToggle; private static O5Toggle? _fixCustomFrameRateToggle; + private static O5Toggle? _disableTileCullingToggle; // Planet color overrides: the toggle enables the override, the picker holds the color. A disabled toggle stores // null in AdvancedConfig (no override is applied by PersistencePatch) and blocks the picker. @@ -807,6 +808,22 @@ internal static class RenderConfigWindow }, generateLabel: false ); + + // Disable Tile Culling (AdvancedConfig.DisableTileCulling): prevents tiles from being disabled outside the frustum + _disableTileCullingToggle = CreateToggleField( + ctx, CreateFieldSlot(advRight), + labelKey: "", + defaultValue: true, + value: config.AdvancedConfig.DisableTileCulling, + toggleTextKey: "ui.render_config.disable_tile_culling", + id: "toggle_disable_tile_culling", + onChanged: val => + { + config.AdvancedConfig.DisableTileCulling = val; + MarkConfigModified(); + }, + generateLabel: false + ); // 7-1. Planet Color Settings (Optional). // For each planet: the toggle turns the override on/off (off stores null and blocks/collapses the picker); @@ -1018,6 +1035,7 @@ internal static class RenderConfigWindow _nonTileToggle?.Set(config.AdvancedConfig.NonTile, false); _highResBloomCorrectionToggle?.Set(config.AdvancedConfig.HighResBloomCorrection, false); _fixCustomFrameRateToggle?.Set(config.AdvancedConfig.FixCustomFrameRate, false); + _disableTileCullingToggle?.Set(config.AdvancedConfig.DisableTileCulling, false); // Planet colors: toggle on when an override is stored; the picker shows the stored color or the default and is // blocked without an override @@ -1201,6 +1219,7 @@ internal static class RenderConfigWindow if (_nonTileToggle != null) target.AdvancedConfig.NonTile = _nonTileToggle.Value; if (_highResBloomCorrectionToggle != null) target.AdvancedConfig.HighResBloomCorrection = _highResBloomCorrectionToggle.Value; if (_fixCustomFrameRateToggle != null) target.AdvancedConfig.FixCustomFrameRate = _fixCustomFrameRateToggle.Value; + if (_disableTileCullingToggle != null) target.AdvancedConfig.DisableTileCulling = _disableTileCullingToggle.Value; // Planet Colors target.AdvancedConfig.firePlanetColor = (_firePlanetToggle?.Value == true && _firePlanetPicker != null)