Skip to content

fix(terrain helper): fix terrain helper hook#2320

Draft
doodlum wants to merge 3 commits into
devfrom
fix-terrain-helper
Draft

fix(terrain helper): fix terrain helper hook#2320
doodlum wants to merge 3 commits into
devfrom
fix-terrain-helper

Conversation

@doodlum
Copy link
Copy Markdown
Collaborator

@doodlum doodlum commented May 11, 2026

Summary by CodeRabbit

  • Refactor

    • Centralized terrain material handling to improve stability and reduce conflicts between modules; updated integrations to use the shared dispatch system.
    • Introduced a processed-land marker so terrain setup avoids reprocessing already-handled cells.
  • Chores

    • Bumped terrain helper shader feature version to 1-0-1.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ac9fa260-1be3-4aee-b7a1-bb9c550e1b4c

📥 Commits

Reviewing files that changed from the base of the PR and between c38d208 and b64c05e.

📒 Files selected for processing (5)
  • src/Features/TerrainHelper.cpp
  • src/Hooks.cpp
  • src/Hooks.h
  • src/TruePBR.cpp
  • src/TruePBR.h
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/Hooks.cpp
  • src/TruePBR.cpp
  • src/Hooks.h
  • src/Features/TerrainHelper.cpp

📝 Walkthrough

Walkthrough

Introduce append-only HookChain slots in src/Hooks.h/src/Hooks.cpp, implement thunks and installers that dispatch through those chains, migrate TruePBR and TerrainHelper to register callbacks into Hooks::MaterialHooks, and bump TerrainHelper INI version.

Changes

Material Hooks Centralization

Layer / File(s) Summary
HookChain template & MaterialHooks slots
src/Hooks.h
Adds HookChain<Fn> and Hooks::MaterialHooks typed accessors for TESObjectLAND post, BSLightingShader interceptors, and BSLightingShader post callbacks.
Hooks implementation & installers
src/Hooks.cpp
Adds MaterialHooks registries and thunks that run original SetupMaterial, allow interceptors to short-circuit, run post callbacks, and installs detour/vfunc overrides in Hooks::Install().
TruePBR migration
src/TruePBR.cpp, src/TruePBR.h
Removes local detour/vfunc wrapper structs, adds kPBRProcessedLandFlag, and registers TruePBR handlers into Hooks::MaterialHooks via lambdas calling TruePBR methods.
TerrainHelper update
src/Features/TerrainHelper.cpp
Include Hooks.h and replace direct thunk/detour registrations with MaterialHooks callbacks; TESObjectLAND post callback gates on vanilla result and land cell flag before calling TerrainHelper::TESObjectLAND_SetupMaterial.
INI Version
features/Terrain Helper/Shaders/Features/TerrainHelper.ini
Bumps [Info] Version from 1-0-0 to 1-0-1.

Sequence Diagram(s)

sequenceDiagram
  participant TESObjectLAND
  participant Hooks_cpp as Hooks.cpp
  participant TruePBR
  participant BSLightingShader
  participant TerrainHelper

  TESObjectLAND->>Hooks_cpp: call SetupMaterial()
  Hooks_cpp->>TruePBR: run TESObjectLANDPost interceptors
  alt handled
    TruePBR-->>Hooks_cpp: handled (early return)
    Hooks_cpp-->>TESObjectLAND: return handled
  else not handled
    TruePBR-->>Hooks_cpp: not handled
    Hooks_cpp->>BSLightingShader: call original/vfunc SetupMaterial
    BSLightingShader-->>Hooks_cpp: original result
    Hooks_cpp->>TerrainHelper: run BSLightingShader post callbacks
    TerrainHelper-->>Hooks_cpp: applied
    Hooks_cpp-->>TESObjectLAND: return final result
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • alandtse

Poem

🐇
I hop through code and bundle strings,
Hook chains now mend the broken things.
TruePBR peeks, TerrainHelper paints,
Hooks.cpp keeps the flow in saints.
A happy rabbit springs.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(terrain helper): fix terrain helper hook' describes a bug fix for terrain helper hooks, which aligns with the core objective of resolving a hook conflict between TerrainHelper and TruePBR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-terrain-helper

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 OpenGrep (1.20.0)

OpenGrep fatal error (exit code 2): [00.19][ERROR]: Error: exception Unix_error: No such file or directory stat src/Features/TerrainHelper.cpp
Raised by primitive operation at UTmp.replace_named_pipe_by_regular_file_if_needed in file "libs/commons/UTmp.ml", line 145, characters 8-27
Called from Scan_CLI.replace_target_roots_by_regular_files_where_needed.(fun) in file "src/osemgrep/cli_scan/Scan_CLI.ml", lines 1086-1087, characters 19-65
Called from List_.fast_map in file "libs/commons/List_.ml", line 81, characters 17-20
Called fr


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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 11, 2026

No actionable suggestions for changed features.

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

🤖 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/Hooks.cpp`:
- Around line 952-957: The hooks for TESObjectLAND_SetupMaterial and
BSLightingShader_SetupMaterial are installed unconditionally using SE/AE-only
relocation/vtable access and will crash on VR builds; wrap the
stl::detour_thunk<TESObjectLAND_SetupMaterial>(REL::RelocationID(18368, 18791))
and stl::write_vfunc<0x4,
BSLightingShader_SetupMaterial>(RE::VTABLE_BSLightingShader[0]) calls in a
VR-safe guard (e.g., if (!REL::Module::IsVR()) { ... }) or add VR
relocation/vtable paths similar to the pattern used at lines 947–950 so these
hooks are only applied when not running VR.
🪄 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: 264b89bc-6109-4ce9-b0b8-50001e8be4d9

📥 Commits

Reviewing files that changed from the base of the PR and between 5a59442 and 85cc575.

📒 Files selected for processing (3)
  • src/Features/TerrainHelper.cpp
  • src/Hooks.cpp
  • src/TruePBR.cpp
💤 Files with no reviewable changes (2)
  • src/Features/TerrainHelper.cpp
  • src/TruePBR.cpp

Comment thread src/Hooks.cpp
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 11, 2026

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

Copy link
Copy Markdown
Collaborator

@SkrubbySkrubInAShrub SkrubbySkrubInAShrub left a comment

Choose a reason for hiding this comment

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

doesn't work

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.

Setup hook registration. Do not violate the feature boundary.

@alandtse
Copy link
Copy Markdown
Collaborator

I'll have a fix incoming shortly since no one looks like they're working on this.

@alandtse alandtse force-pushed the fix-terrain-helper branch from 4deca10 to c38d208 Compare May 18, 2026 04:10
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 (1)
src/Features/TerrainHelper.cpp (1)

200-218: 💤 Low value

Consider extracting magic number to a named constant.

The flag value 8 on line 209 has a comment explaining its purpose, but extracting it to a named constant would improve maintainability and make the cross-feature contract with TruePBR more explicit.

♻️ Suggested refactor

Add a constant (perhaps in a shared header or at namespace scope):

// Flag set by TruePBR on land cells it processes; TerrainHelper should skip these.
inline constexpr auto kPBRProcessedFlag = static_cast<RE::OBJ_LAND::Flag>(8);

Then use it in the callback:

-			if (land->data.flags.any(static_cast<RE::OBJ_LAND::Flag>(8))) {
+			if (land->data.flags.any(kPBRProcessedFlag)) {
🤖 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/TerrainHelper.cpp` around lines 200 - 218, The literal flag
value 8 used in the TESObjectLANDPost callback is a magic number; replace it
with a named constant to clarify the cross-feature contract with TruePBR and
improve maintainability. Add an inline constexpr constant (e.g.,
kPBRProcessedFlag) of type RE::OBJ_LAND::Flag at an appropriate shared/namespace
scope, document that it is the flag TruePBR sets on land cells, then update the
check in the lambda (land->data.flags.any(...)) to use kPBRProcessedFlag instead
of the raw casted 8; keep the rest of the TESObjectLANDPost and
BSLightingShaderPost registrations unchanged.
🤖 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.

Nitpick comments:
In `@src/Features/TerrainHelper.cpp`:
- Around line 200-218: The literal flag value 8 used in the TESObjectLANDPost
callback is a magic number; replace it with a named constant to clarify the
cross-feature contract with TruePBR and improve maintainability. Add an inline
constexpr constant (e.g., kPBRProcessedFlag) of type RE::OBJ_LAND::Flag at an
appropriate shared/namespace scope, document that it is the flag TruePBR sets on
land cells, then update the check in the lambda (land->data.flags.any(...)) to
use kPBRProcessedFlag instead of the raw casted 8; keep the rest of the
TESObjectLANDPost and BSLightingShaderPost registrations unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a7207b7-abbd-4dfa-ae1d-0f10708a02e8

📥 Commits

Reviewing files that changed from the base of the PR and between 4deca10 and c38d208.

📒 Files selected for processing (5)
  • features/Terrain Helper/Shaders/Features/TerrainHelper.ini
  • src/Features/TerrainHelper.cpp
  • src/Hooks.cpp
  • src/Hooks.h
  • src/TruePBR.cpp
✅ Files skipped from review due to trivial changes (1)
  • features/Terrain Helper/Shaders/Features/TerrainHelper.ini
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Hooks.h
  • src/TruePBR.cpp
  • src/Hooks.cpp

@alandtse
Copy link
Copy Markdown
Collaborator

@coderabbitai is this the right scope?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Tip

For best results, initiate chat on the files or code changes.

@alandtse: Yes, the scope is appropriate and well-motivated here. The root cause of the broken terrain helper hook is that both TerrainHelper and TruePBR were independently installing detours/vfunc-writes on the same two engine functions (TESObjectLAND::SetupMaterial and BSLightingShader::SetupMaterial). Whichever feature installed its hook last would silently clobber the other.

This tension was already acknowledged when terrain helper was first introduced: "I had to move 2 hooks out of TruePBR class because terrain helper needs to hook them as well." The new PR formalizes a proper solution.

The changes needed to fix the conflict are:

File Why it's in scope
Hooks.h / Hooks.cpp Introduces the HookChain<Fn> / MaterialHooks framework — a single install point that fans out to registered callbacks
TruePBR.cpp Must be updated — it currently owns one of the competing hooks; it needs to switch to callback registration
TerrainHelper.cpp The feature being fixed — switches to callback registration
TerrainHelper.ini Version bump for the fix

The intended behavior is for TruePBR to override terrain materials with PBR textures, and if no PBR material is found, fall back to vanilla behavior and allow TerrainHelper to apply its own modifications. The BSLightingShaderInterceptors chain with early-return semantics in this PR exactly encodes that priority.

The new framework is also a net positive for maintainability — any future feature needing to hook these material functions can register a callback rather than risk clobbering an existing detour. So the scope is minimal for a correct fix, not over-engineered.

Hooks.cpp no longer references TruePBR or TerrainHelper directly. Adds
a small multi-subscriber dispatcher in Hooks::MaterialHooks that each
feature registers against from its own PostPostLoad, restoring the
feature boundary that PR #2210 established while keeping a single
detour/vfunc install per address.

Semantics preserved from the prior consolidated thunk:
- TESObjectLAND::SetupMaterial: vanilla first, then post callbacks in
  registration order; first callback to return true claims the result.
  TruePBR registers a claiming post-callback; TerrainHelper observes.
- BSLightingShader::SetupMaterial: interceptors before vanilla (return
  true to skip vanilla and the post chain), post callbacks after.
  TruePBR is an interceptor; TerrainHelper is post.

A single HookChain<Fn> template backs each slot - range-for over a
vector of function pointers, no std::function, no allocation. Adding a
new dispatch slot is a one-liner accessor.

Registration order is deterministic via Feature::GetFeatureList()
(TruePBR ahead of TerrainHelper), so PBR's claim short-circuits
TerrainHelper on PBR land cells. The flag-8 gate stays in
TerrainHelper as a defensive backstop.
@alandtse alandtse force-pushed the fix-terrain-helper branch from c38d208 to b64c05e Compare May 18, 2026 04:33
@alandtse
Copy link
Copy Markdown
Collaborator

@coderabbitai should the scope have a hyphen?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Tip

For best results, initiate chat on the files or code changes.

@alandtse: It's a style preference — the Conventional Commits spec doesn't mandate a specific format for scopes. That said, the community convention is to use a hyphen for multi-word scopes (e.g. fix(terrain-helper): ...) since spaces can cause parsing issues in some changelog/tooling pipelines. The current fix(terrain helper) mirrors the actual feature folder name (Terrain Helper), which is a reasonable argument for keeping the space.

In short: fix(terrain-helper) would be more conventional and tooling-friendly, but fix(terrain helper) isn't wrong per the spec. If this repo has an established commit convention (e.g. other scopes use hyphens), it'd be worth matching that pattern for consistency.

@alandtse
Copy link
Copy Markdown
Collaborator

@coderabbitai what is the convention for the terrain helper in the past?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search git log for commits mentioning terrain helper scope
git log --oneline --all | grep -i "terrain" | head -40

Length of output: 2586


@alandtse: Based on the git history, the established convention for this repo is terrain helper (with a space, no hyphen). The two directly relevant past commits both use that form:

There's one outlier (fix(terrainhelper): ... in #1068) with no separator at all, but the clear pattern for scoped commits is the space-separated form. So the current PR title fix(terrain helper): fix terrain helper hook is consistent with the repo's own convention.

@alandtse
Copy link
Copy Markdown
Collaborator

@SkrubbySkrubInAShrub please confirm the new build fixes it. I have no idea how to test this. Please note that since this is based on dev, grass lighting must have default settings.

@SkrubbySkrubInAShrub
Copy link
Copy Markdown
Collaborator

@SkrubbySkrubInAShrub please confirm the new build fixes it. I have no idea how to test this. Please note that since this is based on dev, grass lighting must have default settings.

still doesn't seem to work

@doodlum doodlum marked this pull request as draft May 20, 2026 12:20
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.

3 participants