Skip to content

fix(unified-water): water lod z-fighting#2019

Merged
alandtse merged 19 commits into
community-shaders:devfrom
SkrubbySkrubInAShrub:uw-fix-2
Mar 29, 2026
Merged

fix(unified-water): water lod z-fighting#2019
alandtse merged 19 commits into
community-shaders:devfrom
SkrubbySkrubInAShrub:uw-fix-2

Conversation

@SkrubbySkrubInAShrub
Copy link
Copy Markdown
Collaborator

@SkrubbySkrubInAShrub SkrubbySkrubInAShrub commented Mar 28, 2026

fix for the z-fighting in child worldspaces between the water lod and loaded water cells.

Summary by CodeRabbit

  • Performance Improvements

    • Smarter grid-cell–driven water LOD culling for smoother rendering and reduced overhead.
    • Immediate culls for newly built tiles to cut visible pop-in.
    • Cross-thread retry logic to finish deferred culls once tile attachment data is available.
  • Bug Fixes

    • More reliable water visibility when entering/exiting nested child-worldspaces, reducing flicker and glitches.
    • Improved handling when switching worldspaces to avoid stale cull state.

@github-actions
Copy link
Copy Markdown

No actionable suggestions for changed features.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6de64847-e91a-4a18-95c2-93521f541e58

📥 Commits

Reviewing files that changed from the base of the PR and between 1295e97 and 518932d.

📒 Files selected for processing (2)
  • src/Features/UnifiedWater.cpp
  • src/Globals.h
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Globals.h
  • src/Features/UnifiedWater.cpp

📝 Walkthrough

Walkthrough

Adds child-worldspace detection and deferred completion for water LOD-parent culling: new atomic cached TES/worldspace state, grid-cell–driven cull helpers, lifecycle thunks to set/clear deferred culls, and retry sites to complete deferred culls across thread boundaries.

Changes

Cohort / File(s) Summary
UnifiedWater core
src/Features/UnifiedWater.h, src/Features/UnifiedWater.cpp
Added atomic state (currentPlayerWorldSpace, pendingChildWsCull, cachedTes) and TryCompleteDeferredChildWorldspaceCull(RE::TES* tes). Implemented child-worldspace detection and grid-cell driven cull helpers (ShouldCullAtCell, CullWaterParentByGridCells, CullAllWaterLODParents) and deferred-cull tracking.
Worldspace / lifecycle thunks
src/Thunks/TES_SetWorldSpace.cpp, src/Thunks/TES_DestroySkyCell.cpp
Cache/clear player worldspace and cached TES on enter/exit; set/clear pendingChildWsCull; enable/disable water system during child-worldspace transitions; attempt immediate cull when tes->gridCells is available.
Mesh / attach & render hooks
src/Thunks/BGSTerrainBlock_Attach.cpp, src/Thunks/BSWaterShader_SetupGeometry.cpp, src/Thunks/TESWaterSystem_UpdateDisplacementMeshPosition.cpp, src/Thunks/BGSTerrainNode_UpdateWaterMeshSubVisibility.cpp
Added cross-thread retry calls to TryCompleteDeferredChildWorldspaceCull() from Attach, shader setup, and displacement update thunks. BGSTerrainBlock_Attach now also performs immediate culling for newly built tiles in child worldspaces; node visibility now defers to grid-cell parent cull helpers.
Globals
src/Globals.h, src/Globals.cpp
Introduced globals::game::waterSystem (extern declaration and initialization from RE::TESWaterSystem::GetSingleton()); removed a duplicate globals::game::tes declaration.
Minor refactor
src/Thunks/TESWaterSystem_UpdateDisplacementMeshPosition.cpp
Replaced some singleton usages with uw (UnifiedWater) locals and added cross-thread deferred-cull retry call.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
participant Player
participant TES
participant UW as UnifiedWater
participant WaterSys as TESWaterSystem
participant TerrainBlock as BGSTerrainBlock
participant WaterShader as BSWaterShader

Player->>TES: TES_SetWorldSpace::thunk (player worldspace change)
TES->>UW: cache worldspace & cachedTes; set/clear pendingChildWsCull
alt entering child worldspace
UW->>WaterSys: enable water cache / set worldspace
UW->>UW: CullAllWaterLODParents() if tes->gridCells present
UW-->>UW: set pendingChildWsCull (if cells absent)
else leaving child worldspace
UW->>UW: clear pendingChildWsCull, reset currentPlayerWorldSpace, clear cachedTes
UW->>WaterSys: clear water cache worldspace
end

Note over TerrainBlock,WaterShader,WaterSys: deferred cull completion points
TerrainBlock->>UW: BGSTerrainBlock_Attach::thunk -> TryCompleteDeferredChildWorldspaceCull()
WaterShader->>UW: BSWaterShader_SetupGeometry::thunk -> TryCompleteDeferredChildWorldspaceCull()
WaterSys->>UW: TESWaterSystem_UpdateDisplacementMeshPosition::thunk -> TryCompleteDeferredChildWorldspaceCull()
UW->>UW: complete deferred cull and clear pending flag

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • sicsix
  • alandtse

Poem

"I hop through code and shimmering tide,
I mark child worlds where waters hide.
If culls delay, I nudge again — no fear;
Tiles hush, LODs settle, edges clear.
A rabbit cheers: the lakes appear! 🐇🌊"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(unified-water): water lod z-fighting' directly addresses the primary change: fixing z-fighting issues between water LOD and loaded water cells in child worldspaces through improved culling logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

pre-commit-ci Bot and others added 4 commits March 28, 2026 13:43
Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
@SkrubbySkrubInAShrub SkrubbySkrubInAShrub marked this pull request as ready for review March 28, 2026 14:37
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Features/UnifiedWater.cpp`:
- Around line 21-54: CullWaterParentByGridCells currently returns true as soon
as it finds any attached child which causes pendingChildWsCull to be cleared too
early; instead, make the function determine whether the deferred pass is truly
complete by scanning all children and only clearing pendingChildWsCull when no
children remain that are inside the grid but currently unattached (i.e.,
children that could flip to kAttached in subsequent frames). Modify
CullWaterParentByGridCells (and the call sites that set/clear
pendingChildWsCull) to: 1) iterate all children and track two booleans —
foundAttachedCell (existing behavior) and hasPotentiallyAttachableChild (child
within grid bounds but not currently attached); 2) set child->SetAppCulled(cull)
as before; and 3) return a value that only clears pendingChildWsCull when
foundAttachedCell is true AND hasPotentiallyAttachableChild is false (so
BGSTerrainNode_UpdateWaterMeshSubVisibility or later attachments can still
trigger another pass).
- Around line 394-395: DataLoaded() may return before uw.waterCache is
allocated, so update the hooks that call uw.waterCache->SetCurrentWorldSpace
(and the other calls around the same area) to check for a valid pointer first;
in the functions handling worldspace transitions (the hooks that call
SetCurrentWorldSpace and the related calls at the later block), guard with if
(!uw.waterCache) { /* gracefully disable/return */ } and either early-return or
disable/unregister the UnifiedWater feature so a missing/invalid water mesh
doesn't cause a null-deref; reference the uw.waterCache pointer and the
DataLoaded() control flow when locating the hook code to apply this guard.
- Around line 594-600: The render-thread branch that accesses tes->gridCells and
*gWaterLOD (guarded by pendingChildWsCull, currentPlayerWorldSpace, gWaterLOD,
cachedTes and calling CullAllWaterLODParents inside BSWaterShader_SetupGeometry)
must not walk or read the TES grid or NiNode tree; move this deferred
child-world cull off the render thread and perform it on the game thread using
the existing retry point in TESWaterSystem_UpdateDisplacementMeshPosition::thunk
(or schedule a task that runs there), so do not dereference cachedTes->gridCells
or *gWaterLOD on the render thread—instead mark the work and enqueue/trigger the
game-thread worker (or run CullAllWaterLODParents from the thunk) and clear
pendingChildWsCull only after the game-thread cull completes; also avoid racing
with BGSTerrainBlock_Attach/Detach by using the game-thread context for all
scene-graph reads.
🪄 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

Run ID: 49080823-3975-4056-891a-2404f58ef704

📥 Commits

Reviewing files that changed from the base of the PR and between d42bcf6 and be9be59.

📒 Files selected for processing (2)
  • src/Features/UnifiedWater.cpp
  • src/Features/UnifiedWater.h

Comment thread src/Features/UnifiedWater.cpp Outdated
Comment thread src/Features/UnifiedWater.cpp
Comment thread src/Features/UnifiedWater.cpp Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 28, 2026

✅ A pre-release build is available for this PR:
Download

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
src/Features/UnifiedWater.cpp (3)

579-594: Consider extracting the per-shape cull logic to reduce duplication.

This block duplicates the cell-state lookup and cull logic from CullWaterParentByGridCells. While the context is slightly different (iterating built pairs vs. node children), a small helper could unify the cell-lookup-and-cull pattern.

♻️ Sketch of a shared helper
// Near the top with other static helpers
static bool ShouldCullAtCell(RE::TES* tes, int32_t cellX, int32_t cellY)
{
    if (!tes || !tes->gridCells)
        return false;
    const auto& gridCells = tes->gridCells;
    const int32_t offsetX = tes->currentGridX - static_cast<int32_t>(gridCells->length >> 1);
    const int32_t offsetY = tes->currentGridY - static_cast<int32_t>(gridCells->length >> 1);
    const int32_t length = static_cast<int32_t>(gridCells->length);
    const int32_t ix = cellX - offsetX;
    const int32_t iy = cellY - offsetY;
    if (ix >= 0 && iy >= 0 && ix < length && iy < length) {
        if (const auto cell = gridCells->GetCell(ix, iy); cell && cell->cellState.any(
            RE::TESObjectCELL::CellState::kAttached,
            static_cast<RE::TESObjectCELL::CellState>(6)))
            return true;
    }
    return false;
}

Then use it in both CullWaterParentByGridCells and the BGSTerrainBlock_Attach loop.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Features/UnifiedWater.cpp` around lines 579 - 594, Extract the repeated
grid-cell culling logic into a static helper (e.g. ShouldCullAtCell) that
accepts a RE::TES* tes and cell coordinates (cellX, cellY) and returns a bool;
move the offset/length/gridCells checks and the cell->cellState.any(...) check
into that helper, then replace the inline logic in the BGSTerrainBlock_Attach
loop (the built iteration using ix/iy and shape->SetAppCulled) and in
CullWaterParentByGridCells to call ShouldCullAtCell(tes, instruction->x,
instruction->y) (or the appropriate node child coordinates) and pass its result
to SetAppCulled, preserving the existing condition semantics and null checks.

55-57: Document the magic cell state value.

static_cast<RE::TESObjectCELL::CellState>(6) is used here and again at line 590, but without explanation. Consider adding a brief comment or defining a named constant for clarity.

📝 Suggested documentation
 		if (x >= 0 && y >= 0 && x < length && y < length) {
 			const auto cell = gridCells->GetCell(x, y);
+			// CellState::kAttached (5) or state 6 (post-attach loaded) indicate the cell has loaded water
 			if (cell && cell->cellState.any(
 							RE::TESObjectCELL::CellState::kAttached,
 							static_cast<RE::TESObjectCELL::CellState>(6))) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Features/UnifiedWater.cpp` around lines 55 - 57, Replace the unexplained
magic cast static_cast<RE::TESObjectCELL::CellState>(6) used inside the
cell->cellState.any check with a named constant or enum alias (e.g.,
kSomeCellState or kCellStateXYZ) and add a brief comment explaining what that
state represents; update both occurrences (the check in UnifiedWater.cpp and the
other at the later occurrence around line 590) to use the new constant so the
meaning is clear instead of using the raw value 6 while keeping the condition
logic unchanged.

622-627: Consider adding a brief comment explaining the acceptable data race on gridCells.

The underlying TES and scene-graph data accessed in TryCompleteDeferredChildWorldspaceCull are not protected beyond the atomic pointer handoff. While cachedTes is correctly synchronized with acquire-release semantics, gridCells and cell state can be modified concurrently by game-thread hooks (BGSTerrainBlock_Attach/Detach). This appears intentional: the deferred cull mechanism with pendingChildWsCull retries on subsequent frames, and a stale cell-state read simply causes incorrect culling for one frame. Adding a comment explaining why this race is benign would clarify the design for future maintainers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Features/UnifiedWater.cpp` around lines 622 - 627, Add a short
explanatory comment above the fallback deferred cull block that notes the
accepted data race: explain that TryCompleteDeferredChildWorldspaceCull is
invoked with globals::features::unifiedWater and the atomic pointer cachedTes
(loaded with memory_order_acquire), but gridCells and cell state may be
concurrently modified by game-thread hooks (BGSTerrainBlock_Attach/Detach);
state the that this is intentional because pendingChildWsCull will retry on
subsequent frames and a stale read only affects culling for a single frame, so
no additional synchronization is required. Mention the relevant symbols
cachedTes, gridCells, TryCompleteDeferredChildWorldspaceCull, and
pendingChildWsCull in the comment to guide future maintainers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/Features/UnifiedWater.cpp`:
- Around line 579-594: Extract the repeated grid-cell culling logic into a
static helper (e.g. ShouldCullAtCell) that accepts a RE::TES* tes and cell
coordinates (cellX, cellY) and returns a bool; move the offset/length/gridCells
checks and the cell->cellState.any(...) check into that helper, then replace the
inline logic in the BGSTerrainBlock_Attach loop (the built iteration using ix/iy
and shape->SetAppCulled) and in CullWaterParentByGridCells to call
ShouldCullAtCell(tes, instruction->x, instruction->y) (or the appropriate node
child coordinates) and pass its result to SetAppCulled, preserving the existing
condition semantics and null checks.
- Around line 55-57: Replace the unexplained magic cast
static_cast<RE::TESObjectCELL::CellState>(6) used inside the cell->cellState.any
check with a named constant or enum alias (e.g., kSomeCellState or
kCellStateXYZ) and add a brief comment explaining what that state represents;
update both occurrences (the check in UnifiedWater.cpp and the other at the
later occurrence around line 590) to use the new constant so the meaning is
clear instead of using the raw value 6 while keeping the condition logic
unchanged.
- Around line 622-627: Add a short explanatory comment above the fallback
deferred cull block that notes the accepted data race: explain that
TryCompleteDeferredChildWorldspaceCull is invoked with
globals::features::unifiedWater and the atomic pointer cachedTes (loaded with
memory_order_acquire), but gridCells and cell state may be concurrently modified
by game-thread hooks (BGSTerrainBlock_Attach/Detach); state the that this is
intentional because pendingChildWsCull will retry on subsequent frames and a
stale read only affects culling for a single frame, so no additional
synchronization is required. Mention the relevant symbols cachedTes, gridCells,
TryCompleteDeferredChildWorldspaceCull, and pendingChildWsCull in the comment to
guide future maintainers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4d57451f-098c-455b-b198-ec135692c8b5

📥 Commits

Reviewing files that changed from the base of the PR and between c890c90 and 17e8edd.

📒 Files selected for processing (2)
  • src/Features/UnifiedWater.cpp
  • src/Features/UnifiedWater.h
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Features/UnifiedWater.h

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/Features/UnifiedWater.cpp (1)

622-629: ⚠️ Potential issue | 🟠 Major

Data race accessing tes->gridCells from render thread.

While the code comments acknowledge staleness, the actual concern is a data race: cachedTes.load() is atomic, but dereferencing tes->gridCells and iterating over grid cells in TryCompleteDeferredChildWorldspaceCull is not synchronized. The game thread can concurrently modify gridCells via BGSTerrainBlock_Attach/Detach, leading to undefined behavior.

If the render-thread fallback is needed for responsiveness, consider:

  1. Moving the deferred cull entirely to game-thread hooks (you already have two game-thread retry points at lines 502 and 689)
  2. Or using a mutex/spinlock around grid access

Additionally, line 627 introduces uw which is redundant with singleton already defined at line 621.

♻️ Minimal fix: remove render-thread fallback and rely on game-thread retries
-	// Render-thread fallback for deferred child-worldspace cull completion.
-	// cachedTes/grid state can be stale while the game thread mutates terrain state.
-	// pendingChildWsCull keeps retrying, so stale reads only delay culling for a frame.
-	{
-		auto& uw = globals::features::unifiedWater;
-		uw.TryCompleteDeferredChildWorldspaceCull(singleton.cachedTes.load(std::memory_order_acquire));
-	}
+	// Deferred child-worldspace cull is handled by game-thread hooks
+	// (BGSTerrainBlock_Attach, TESWaterSystem_UpdateDisplacementMeshPosition).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5c1d5385-4dc7-46d9-a5ed-d372cf105589

📥 Commits

Reviewing files that changed from the base of the PR and between 17e8edd and 5f3bb69.

📒 Files selected for processing (2)
  • src/Features/UnifiedWater.cpp
  • src/Features/UnifiedWater.h
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Features/UnifiedWater.h

Copy link
Copy Markdown
Collaborator

@alandtse alandtse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See if we should use global.

Comment thread src/Features/UnifiedWater.cpp Outdated
@SkrubbySkrubInAShrub
Copy link
Copy Markdown
Collaborator Author

the AI comment can't be fully addressed because any change I try breaks the fix.

Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/Features/UnifiedWater.cpp (1)

624-627: ⚠️ Potential issue | 🔴 Critical

Keep deferred child-world culling off the render thread.

TryCompleteDeferredChildWorldspaceCull() walks tes->gridCells and mutates the gWaterLOD tree. Calling it from BSWaterShader_SetupGeometry still races BGSTerrainBlock_Attach/Detach; the atomics here only publish pointer values, they do not make either structure or lifetime thread-safe.

🧵 Safer direction
-	// Render-thread fallback for deferred child-worldspace cull completion.
-	// cachedTes/grid state can be stale while the game thread mutates terrain state.
-	// pendingChildWsCull keeps retrying, so stale reads only delay culling for a frame.
-	uw.TryCompleteDeferredChildWorldspaceCull(uw.cachedTes.load(std::memory_order_acquire));
+	// Keep deferred child-world culling on the existing game-thread retry points
+	// in BGSTerrainBlock_Attach and TESWaterSystem_UpdateDisplacementMeshPosition.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Features/UnifiedWater.cpp` around lines 624 - 627, The call to
TryCompleteDeferredChildWorldspaceCull from BSWaterShader_SetupGeometry is
unsafe because TryCompleteDeferredChildWorldspaceCull walks tes->gridCells and
mutates gWaterLOD while BGSTerrainBlock_Attach/Detach run on the game thread;
remove or gate the direct call (the
uw.TryCompleteDeferredChildWorldspaceCull(...) invocation that passes
uw.cachedTes.load(...)) so no traversal/mutation runs on the render thread;
instead set a render-to-game signal (e.g., set pendingChildWsCull or enqueue a
task) and ensure the actual TryCompleteDeferredChildWorldspaceCull invocation
executes on the game thread or via the existing retry mechanism managed by the
game loop, keeping only atomic pointer publishes on the render thread and moving
all grid traversal/mutation to the game-thread handler.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Features/UnifiedWater.cpp`:
- Around line 501-503: The game-thread retry paths (e.g., the call through
TryCompleteDeferredChildWorldspaceCull and the other retry blocks around the
commented ranges) are still reading globals::game::tes during the
TES_SetWorldSpace::thunk transition; change those retry closures to capture and
use the stored cachedTes (the value saved in TES_SetWorldSpace::thunk before
func() is invoked) instead of reading globals::game::tes so the immediate
cull/update logic runs against the correct worldspace; specifically, update the
retry lambdas/posted tasks invoked by TryCompleteDeferredChildWorldspaceCull and
the similar retry code at the other noted locations (around 588-595 and 684-687)
to accept/use cachedTes (or pass it in) rather than referencing
globals::game::tes.

---

Duplicate comments:
In `@src/Features/UnifiedWater.cpp`:
- Around line 624-627: The call to TryCompleteDeferredChildWorldspaceCull from
BSWaterShader_SetupGeometry is unsafe because
TryCompleteDeferredChildWorldspaceCull walks tes->gridCells and mutates
gWaterLOD while BGSTerrainBlock_Attach/Detach run on the game thread; remove or
gate the direct call (the uw.TryCompleteDeferredChildWorldspaceCull(...)
invocation that passes uw.cachedTes.load(...)) so no traversal/mutation runs on
the render thread; instead set a render-to-game signal (e.g., set
pendingChildWsCull or enqueue a task) and ensure the actual
TryCompleteDeferredChildWorldspaceCull invocation executes on the game thread or
via the existing retry mechanism managed by the game loop, keeping only atomic
pointer publishes on the render thread and moving all grid traversal/mutation to
the game-thread handler.
🪄 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

Run ID: dbc75277-af19-4cec-bded-afb52129c23f

📥 Commits

Reviewing files that changed from the base of the PR and between 5f3bb69 and 1ea544e.

📒 Files selected for processing (3)
  • src/Features/UnifiedWater.cpp
  • src/Globals.cpp
  • src/Globals.h

Comment thread src/Features/UnifiedWater.cpp
@alandtse
Copy link
Copy Markdown
Collaborator

Is it because the Singleton is null when grabbed by globals? I believe you had mentioned that was also part of the issue with UW.

@SkrubbySkrubInAShrub
Copy link
Copy Markdown
Collaborator Author

@coderabbitai resume

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

✅ Actions performed

Reviews resumed.

@SkrubbySkrubInAShrub
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Globals.h (1)

213-220: ⚠️ Potential issue | 🟡 Minor

Duplicate declaration of tes.

extern RE::TES* tes; appears on both Line 213 and Line 220. This is likely a merge artifact and should be removed.

🔧 Proposed fix
 		extern RE::TES* tes;
 		extern RE::TESWaterSystem* waterSystem;
 		extern bool isVR;
 		extern RE::MemoryManager* memoryManager;
 		extern RE::INISettingCollection* iniSettingCollection;
 		extern RE::INIPrefSettingCollection* iniPrefSettingCollection;
 		extern RE::GameSettingCollection* gameSettingCollection;
-		extern RE::TES* tes;
 		extern float* cameraNear;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Globals.h` around lines 213 - 220, Remove the duplicate extern
declaration of the global pointer symbol `tes` in the Globals.h declarations
block: locate the two lines declaring `extern RE::TES* tes;` and delete the
redundant one so only a single `extern RE::TES* tes;` remains; verify
surrounding externs (`waterSystem`, `isVR`, `memoryManager`,
`iniSettingCollection`, `iniPrefSettingCollection`, `gameSettingCollection`) are
unchanged and the header still compiles.
🧹 Nitpick comments (1)
src/Features/UnifiedWater.cpp (1)

19-20: Document the magic CellState value.

The engine transition state 6 is undocumented. Consider adding a brief comment explaining where this value comes from (e.g., reverse engineering notes or RE library reference) to aid future maintainers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Features/UnifiedWater.cpp` around lines 19 - 20, Add a short explanatory
comment next to kTransitionAttachedCellState that documents that the magic value
6 corresponds to the engine's "transition/attached" CellState
(RE::TESObjectCELL::CellState) used during cell transitioning, and note the
provenance (e.g., discovered via reverse-engineering the game engine or
confirmed from the RE library/reference) so future maintainers know why the
static_cast to that enum uses 6.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/Globals.h`:
- Around line 213-220: Remove the duplicate extern declaration of the global
pointer symbol `tes` in the Globals.h declarations block: locate the two lines
declaring `extern RE::TES* tes;` and delete the redundant one so only a single
`extern RE::TES* tes;` remains; verify surrounding externs (`waterSystem`,
`isVR`, `memoryManager`, `iniSettingCollection`, `iniPrefSettingCollection`,
`gameSettingCollection`) are unchanged and the header still compiles.

---

Nitpick comments:
In `@src/Features/UnifiedWater.cpp`:
- Around line 19-20: Add a short explanatory comment next to
kTransitionAttachedCellState that documents that the magic value 6 corresponds
to the engine's "transition/attached" CellState (RE::TESObjectCELL::CellState)
used during cell transitioning, and note the provenance (e.g., discovered via
reverse-engineering the game engine or confirmed from the RE library/reference)
so future maintainers know why the static_cast to that enum uses 6.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f8c0a1df-e146-48ee-9eb9-9a6b8600ebe5

📥 Commits

Reviewing files that changed from the base of the PR and between 5f3bb69 and 1295e97.

📒 Files selected for processing (3)
  • src/Features/UnifiedWater.cpp
  • src/Globals.cpp
  • src/Globals.h
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Globals.cpp

@SkrubbySkrubInAShrub
Copy link
Copy Markdown
Collaborator Author

Is it because the Singleton is null when grabbed by globals? I believe you had mentioned that was also part of the issue with UW.

seems to work now after some rejigging

@alandtse alandtse merged commit 3a0dc42 into community-shaders:dev Mar 29, 2026
17 checks passed
ParticleTroned pushed a commit to ParticleTroned/skyrim-community-shaders that referenced this pull request May 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants