fix(unified-water): cell transition flicker#2419
Conversation
📝 WalkthroughWalkthroughUnifiedWater refactors water attachment and shader computation by introducing worldspace change hooks, inlining terrain block water generation, updating grid-based culling logic, removing a redundant global waterSystem pointer, and adjusting shader uniform and displacement calculations to use singleton flowmap state. ChangesUnified Water Attachment and Shader Lifecycle
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
No actionable suggestions for changed features. |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Features/UnifiedWater.cpp (1)
243-267:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winDon't install these hooks until Unified Water finishes initializing.
DataLoaded()can return beforewaterCacheand the mesh pointers are created, butPostPostLoad()still registers the new worldspace/attach hooks. The next worldspace change or terrain attach then dereferences null feature state instead of failing closed. Please gate hook registration behind successful initialization, or early-out each thunk tofunc(...)when Unified Water is unavailable.As per coding guidelines,
src/**/*.{h,cpp}: "Include proper resource management and graceful degradation error handling in all DirectX code to prevent crashes from malformed configurations".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Features/UnifiedWater.cpp` around lines 243 - 267, PostPostLoad currently installs detours (TES_SetWorldSpace, TES_DestroySkyCell, BGSTerrainBlock_Attach/Detach, BGSTerrainNode_UpdateWaterMeshSubVisibility, TESWaterSystem_InitializeWater_SetWaterShaderMaterialParams, BSWaterShaderMaterial_ComputeCRC32) before UnifiedWater has finished creating waterCache and mesh pointers, causing null derefs; fix by gating hook registration in UnifiedWater::PostPostLoad behind a successful initialization check (e.g., DataLoaded() && waterCache && mesh pointers or an IsInitialized() method) and only call stl::detour_thunk/write_thunk_call/write_vfunc when that check passes, or alternatively add an early-return guard in each thunk (BGSTerrainBlock_Attach, BGSTerrainBlock_Detach, TES_SetWorldSpace, BGSTerrainNode_UpdateWaterMeshSubVisibility, etc.) that falls back to calling the original func when UnifiedWater is unavailable; ensure both approaches are used where appropriate so hooks are safe if initialization hasn't completed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/Features/UnifiedWater.cpp`:
- Around line 389-394: The loop is mutating water->GetChildren() while
range-iterating it, which can invalidate iteration; instead first copy the child
pointers into a separate container and then iterate that copy to call
waterSystem->RemoveWater(child.get()) and water->DetachChild(child.get()).
Locate the block that currently iterates over water->GetChildren(), build a
temporary vector (or list) of the child shared_ptr/raw pointers, then perform
removal/detach using that temporary collection to avoid mutating the original
list during iteration.
---
Outside diff comments:
In `@src/Features/UnifiedWater.cpp`:
- Around line 243-267: PostPostLoad currently installs detours
(TES_SetWorldSpace, TES_DestroySkyCell, BGSTerrainBlock_Attach/Detach,
BGSTerrainNode_UpdateWaterMeshSubVisibility,
TESWaterSystem_InitializeWater_SetWaterShaderMaterialParams,
BSWaterShaderMaterial_ComputeCRC32) before UnifiedWater has finished creating
waterCache and mesh pointers, causing null derefs; fix by gating hook
registration in UnifiedWater::PostPostLoad behind a successful initialization
check (e.g., DataLoaded() && waterCache && mesh pointers or an IsInitialized()
method) and only call stl::detour_thunk/write_thunk_call/write_vfunc when that
check passes, or alternatively add an early-return guard in each thunk
(BGSTerrainBlock_Attach, BGSTerrainBlock_Detach, TES_SetWorldSpace,
BGSTerrainNode_UpdateWaterMeshSubVisibility, etc.) that falls back to calling
the original func when UnifiedWater is unavailable; ensure both approaches are
used where appropriate so hooks are safe if initialization hasn't completed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: d097637d-9359-4d94-9664-512adb7861f2
📒 Files selected for processing (4)
src/Features/UnifiedWater.cppsrc/Features/UnifiedWater.hsrc/Globals.cppsrc/Globals.h
💤 Files with no reviewable changes (2)
- src/Globals.h
- src/Globals.cpp
|
✅ A pre-release build is available for this PR: |
Fixes flicker after interior -> exterior transition by patching a 2nd path which iterates the root LOD multibound causing materials to be initialized twice.
This PR reverts #1998, #2019, #2353, #2367 and supersedes PR #2391.
Summary by CodeRabbit