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)