Skip to content

Conversation

@Basilisk3
Copy link
Collaborator

@Basilisk3 Basilisk3 commented Aug 16, 2025

Description of the proposed changes

As per the title. Screenshots can be found below.

Checklist

Summary by CodeRabbit

  • Bug Fixes
    • Improved prop level-of-detail (LOD): LOD now scales with prop size, adds explicit cutoffs for certain tree types, enforces a maximum for others, redistributes per-LOD cutoffs proportionally, and refines rounding so cutoffs snap to the nearest 10 — reducing pop-ins and making broken tree groups easier to spot.
  • Tweaks
    • Adjusted physical sizes for some deposit props so their visibility and interaction better match intended scale.
  • Changelog
    • Added entry describing the LOD tweak and its visible effects.

✏️ Tip: You can customize this high-level summary in your review settings.

@Basilisk3 Basilisk3 requested review from BlackYps and Garanas August 16, 2025 09:58
@Basilisk3 Basilisk3 added area: graphics Anything Related to the Game Graphics area: baking of blueprints related to baking properties into blueprints via workflows labels Aug 16, 2025
@BlackYps
Copy link
Contributor

I'm not sure if this is going in a direction that is helpful to address the root problem. In theory the changing of LOD levels should ideally be barely noticeable to the user. When the lowest level looks better than the level before that, then we should investigate there.

@Basilisk3
Copy link
Collaborator Author

Basilisk3 commented Aug 16, 2025

I'm not sure if this is going in a direction that is helpful to address the root problem.

@BlackYps This PR is designed to only give us an additional knob to play with. Right now, the blueprint values are skipped entirely, but I think it would be beneficial to at least have the option for blueprint values to take precedence, if desired.

In theory the changing of LOD levels should ideally be barely noticeable to the user. When the lowest level looks better than the level before that, then we should investigate there.

After some additional testing and further contemplation, I think the way the second LOD looks is fine, and the issue is that it’s currently being used at too-high zoom levels. I addressed this in my other PR.

This is the maximum zoom level at which the second LOD level is currently visible:

LOD_current

As you can see, tree groups are more difficult to identify, and the overall look feels a bit out of place.

Displaying the most detailed LOD level for longer

You made the suggestion, that the second, less detailed LOD level could be removed entirely. I found the idea intriguing, so I tested it.

With the second LOD level retained:
LOD2

With the second LOD level removed:
NOLOD2jpg

Visually, I prefer the first screenshot (with the second LOD level retained). Removing it, however, eliminates the transition between the LOD levels, which looks smoother and more modern - albeit with a potential performance cost that still needs to be investigated.

In summary, I think a good argument can be made for both keeping and removing the second LOD. I would prefer to keep it for now and make the LOD behavior more similar to how it was pre-patch, while retaining the increased maximum render distance of trees (which is what I am doing here and in #6907).

@Garanas
Copy link
Member

Garanas commented Aug 17, 2025

If the goal is to prefer showing higher LODs sooner then you can also adjust the formula found here:

-- give more emphasis to the x / z value as that is easier to see in the average camera angle
local weighted = 0.40 * sx + 0.2 * sy + 0.4 * sz
if prop.ScriptClass == 'Tree' or prop.ScriptClass == 'TreeGroup' then
weighted = 10.0
end
-- https://www.desmos.com/calculator (0.9 * sqrt(100 * 500 * x))
local lod = 0.9 * MathSqrt(100 * 500 * weighted)
if prop.Display and prop.Display.Mesh and prop.Display.Mesh.LODs then
local n = TableGetn(prop.Display.Mesh.LODs)
for k = 1, n do
local data = prop.Display.Mesh.LODs[k]
-- https://www.desmos.com/calculator (x * x)
local factor = (k / n) * (k / n)
local LODCutoff = factor * lod
-- sanitize the value
data.LODCutoff = MathFloor(LODCutoff / 10 + 1) * 10
end
end
end

If you change local factor = (k / n) * (k / n) to local factor = (k / n) * (k / n) * (k / n) it will preference the higher LODs while the maximum render distance remains unchanged. Additionally, you can change add 10 to the sanitized result. As an example:

INFO: /env/redrocks/props/trees/groups/redtree01_group1_prop.bp	LOD:	1	4.3744492530823	 -> 	1.4581497907639
INFO: /env/redrocks/props/trees/groups/redtree01_group1_prop.bp	LOD:	2	69.991188049316	 -> 	46.660793304443
INFO: /env/redrocks/props/trees/groups/redtree01_group1_prop.bp	LOD:	3	354.3303527832	 -> 	354.3303527832
INFO: /env/evergreen/props/trees/groups/pine06_big_groupb_prop.bp	LOD:	1	6.8673510551453	 -> 	2.2891170978546
INFO: /env/evergreen/props/trees/groups/pine06_big_groupb_prop.bp	LOD:	2	109.87761688232	 -> 	73.251747131348
INFO: /env/evergreen/props/trees/groups/pine06_big_groupb_prop.bp	LOD:	3	556.25537109375	 -> 	556.25537109375

Looking at these results it may also be interesting to add a flat value of 10 to each level. Because a LODCutoff of 4.3 won't show up any time soon, let alone 1.45 😃 !

@Basilisk3
Copy link
Collaborator Author

Basilisk3 commented Aug 17, 2025

@Garanas Good catch, local factor = (k / n) * (k / n) * (k / n) was the first thing I tried when making the PR, but thanks for steering me back toward the correct solution anyway. I tried local factor = (k / n) * (k / n) * (k / n) * (k / n) now, and it reverts the starting zoom level for the least detailed LOD back to how it was pre-patch. Since this is a more aggressive formula, I also went with adding a flat value of 30 instead of 10.

It looks promising on Seton's, but I haven't tested very many other maps yet. I think red maps still need some tuning, the most detailed LOD of a lot of the trees there is still not visible for very long.

@Rhaelya Can you give these changes a try to see if this does what you are looking for? I did some preliminary testing on Seton's, and I think this is the outcome we're after. You won't need the changes from #6907 to test the new LOD levels now.

@Basilisk3
Copy link
Collaborator Author

I did some more testing on a variety of maps, and found no glaring issues. If the skip the automatic computation of LOD part of the PR isn't liked, I'll revert it. I think it's a fine idea but not essential.

@BlackYps Since you are more experienced than I am, can you take another look at this?

@BlackYps
Copy link
Contributor

Sorry, this conversation stalled a bit. I'd say we should change much of how this whole function works. Instead of doing indirect changes to the mathematical formula, we should define explicit ranges, for example 50, 100, 200 and then we scale these according to the prop size. This way you have more control over when which LOD level shows and the code is easier to read as well.
If we define separate values for tree groups and single trees we can get back the behaviour that you can spot broken tree groups by noticing the LOD change.

In the end this should all be baked in the blueprint of the props. I remember there is a tool for it, but I don't remember any details. I think @Garanas should know.

@Garanas
Copy link
Member

Garanas commented Oct 19, 2025

I'd say we should change much of how this whole function works. Instead of doing indirect changes to the mathematical formula, we should define explicit ranges, for example 50, 100, 200 and then we scale these according to the prop size. This way you have more control over when which LOD level shows and the code is easier to read as well.

I like this idea!

There's a workflow that runs the blueprints.lua file and bakes properties accordingly. See also:

It creates a new pull request with the new baked in results. Therefore we'd first need to merge this PR to adjust the formula. Then run the workflow to bake it into the blueprints, which opens as a new pull request. For more information:

@BlackYps
Copy link
Contributor

@Basilisk3 do you intend to finish this? Otherwise I would pick it up

@coderabbitai
Copy link

coderabbitai bot commented Nov 23, 2025

Walkthrough

Compute a size-weighted metric from sx, sy, sz to set maxLod (180 * weightedLodSize); for Tree/TreeGroup with exactly 3 LODs use cutoffs [40, 165, 640] and return, otherwise cap maxLod at 640. Per-LOD cutoffs are (n / levels) * maxLod, rounded to nearest 10. Also update sizes for two prop blueprints and add a changelog entry.

Changes

Cohort / File(s) Summary
LOD Calculation & Changelog
changelog/snippets/feature.6906.md, lua/system/blueprints-props.lua
Add changelog entry. Replace previous LOD formula with a size-weighted approach: compute weightedLodSize from sx, sy, sz, set maxLod = 180 * weightedLodSize. For Tree/TreeGroup with exactly 3 LODs set explicit LODCutoff [40, 165, 640] and return; otherwise cap maxLod at 640. Compute per-LOD LODCutoff = (n / levels) * maxLod and round to nearest 10 using floor((LODCutoff + 5) / 10) * 10. No public API changes.
Prop Blueprint Size Updates
env/Common/Props/hydrocarbonDeposit01_prop.bp, env/Common/Props/massDeposit01_prop.bp
Adjust prop size fields: hydrocarbonDeposit01_prop.bp SizeX, SizeY, SizeZ changed from (0.1, 0.1, 0.1) to (1.0, 0.2, 1.0); massDeposit01_prop.bp SizeX, SizeZ increased from 0.1 to 0.9. Collision/other fields unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review weightedLodSize computation and units (sx/sy/sz use and weighting).
  • Verify interaction between the 180 multiplier and the 640 cap for edge cases.
  • Confirm Tree/TreeGroup 3-LOD hardcoded cutoffs and early-return are intended.
  • Check rounding behavior near boundary values and for very small props.
  • Validate that the prop size changes align with intended visual/collision outcomes.

Poem

🐇 I measured x, y, z with a curious paw,
Tuned cutoffs by size and skipped a flaw.
Three trees sing at forty, one-sixty-five, six-forty bright,
Small bumps grown broader, now seen in light.
A rabbit hops — LODs look just right 🌿

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is incomplete. It references screenshots without embedding them, lacks detailed explanation of the changes, and provides minimal testing details despite the changelog indicating preliminary testing on multiple maps. Expand description with technical details of the formula changes, embed or link screenshots, describe testing scope (maps tested, prop types), and clarify the size adjustment rationale for deposit props.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: a tweak to the LOD calculation formula for props, which is the primary focus of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63c8e79 and e888cf7.

📒 Files selected for processing (2)
  • env/Common/Props/hydrocarbonDeposit01_prop.bp (1 hunks)
  • env/Common/Props/massDeposit01_prop.bp (1 hunks)
🔇 Additional comments (2)
env/Common/Props/massDeposit01_prop.bp (1)

28-30: LGTM - Size adjustments look appropriate for deposit props.

The size increases (0.1 → 0.9 for X and Z dimensions) address the unrealistically small bounding boxes mentioned in the PR discussion. Since this prop is invulnerable and untargetable, the collision detection changes carry minimal risk.

Please verify in-game that the new bounding box dimensions appear correct and don't cause any visual or interaction issues with the deposit model.

env/Common/Props/hydrocarbonDeposit01_prop.bp (1)

31-33: LGTM - Hydrocarbon deposit size adjustments consistent with mass deposit changes.

The size increases (SizeX and SizeZ to 1.0, SizeY to 0.2) mirror the mass deposit adjustments and fix the same unrealistic tiny bounding box issue. The invulnerability ensures collision changes won't introduce gameplay bugs.

Please verify in-game that the new dimensions align properly with the hydrocarbon deposit model and don't cause visual artifacts or interaction problems.


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.

Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62fd371 and 4e6ef89.

📒 Files selected for processing (3)
  • changelog/snippets/feature.6906.md (1 hunks)
  • engine/Core/Categories.lua (1 hunks)
  • lua/system/blueprints-props.lua (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: Documentation - Generate changelog
changelog/snippets/feature.6906.md

[error] 1-1: Changelog verification failed. Invalid format: feature.6906.md. Command 'changelog-verify.sh' exited with code 1.

🔇 Additional comments (1)
lua/system/blueprints-props.lua (1)

124-126: LGTM: Blueprint LOD precedence logic is correct.

The conditional check properly skips automatic LOD computation when the USEBLUEPRINTLOD category is present, allowing blueprint-defined values to take precedence. The logic is sound and aligns with the PR objectives.

@Basilisk3
Copy link
Collaborator Author

Basilisk3 commented Nov 23, 2025

Yes, I intend to finish it. The ability for props to skip the automatic computation of LOD still seems useful to me, but if it's controversial I can revert it to get the more important change (the prop LOD changes) ready. When I tested the LOD changes a while ago, I found no glaring issues, but it would probably be beneficial if someone with more experience in this part of the game took another look.

These are the LOD changes I mean.

So basically this only needs some more feedback and a decision on whether we want to keep the new category that allows us to potentially skip the automatic computation of LODs for select props.

@BlackYps
Copy link
Contributor

I posted what I think is the way forward here: #6906 (comment)
I don't think we need the category. Ideally we come up with a formula that gives us good results, so we eliminate the desire to finetune individual props.

@BlackYps
Copy link
Contributor

While you are at it, I think this formula should be adjusted: local weighted = 0.40 * sx + 0.2 * sy + 0.4 * sz. It seems very unusual to me to just add the dimensions. I am okay with giving less emphasize to the height, but it would make more sense to me to calculate the diagonal length for example.

@Basilisk3
Copy link
Collaborator Author

I removed the new category. As for the weighted formula, I tried a couple of options, but I think the current one works well enough - at least on the maps I tested.

@Basilisk3 Basilisk3 changed the title Add support for props to skip the automatic computation of LODs Tweak the formula used to calculate the level of detail (LOD) for props. Nov 28, 2025
@BlackYps
Copy link
Contributor

I read the whole conversation again, but it's a bit unclear what exactly the goal is. I figured you want to set the cutoff of the first lod level to where it was before we increased the weighted value for trees from 2.6 to 10?
And what maps did you test on? I will soon push a commit to simplify the formulas, so it would be good to know what you are aiming for.

@Basilisk3
Copy link
Collaborator Author

My reasoning can be found here: #6907. The goal is to revert tree group visibility to what it was pre‑patch, while keeping the higher max LOD level the patch introduced. As you can see in the first screenshot, tree group visibility is currently worse than it was pre‑patch, which this PR aims to fix.

I mostly investigated the evergreen props found on maps such as Seton's and Selkie, since these maps and their props are the most popular. Red maps behaved fine as well, though I didn’t check those as thoroughly.

@BlackYps
Copy link
Contributor

I changed the function so it now allows setting explicit values for tree groups and single trees. The tree groups only use lod1 and lod3. This way you can spot broken tree groups because the individual trees render with lod2 on medium zoom ranges. Tested on selkie and the fa and faf props test map. I believe this should solve the problem of not being able to spot broken tree groups.

Unrelated to the tree changes: big props are now visible for longer.

Copy link

@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

Caution

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

⚠️ Outside diff range comments (1)
lua/system/blueprints-props.lua (1)

63-74: isReclaimable uses the wrong category constant

Line 64 duplicates the OBSTRUCTSBUILDING check instead of using a reclaim-related category, so the warning branch can never trigger as intended.

-    local isReclaimable = TableFind(prop.Categories, 'OBSTRUCTSBUILDING')
+    local isReclaimable = TableFind(prop.Categories, 'RECLAIMABLE')

This restores the intended distinction between “blocks building” and “is reclaimable” when emitting warnings.

♻️ Duplicate comments (1)
lua/system/blueprints-props.lua (1)

158-168: Global LOD formula change still requires re-running the bake-blueprints workflow

ProcessLOD is used both at runtime and in BakePropBlueprints, so this new formula will only be persisted to blueprints after the .github/workflows/bake-blueprints.yaml workflow is run again.

As with the previous iteration of this PR, please ensure the bake workflow is triggered after merge (or as a follow-up PR) so all prop blueprints get updated LODCutoff values.

🧹 Nitpick comments (2)
lua/system/blueprints-props.lua (2)

112-119: Confirm the 180 * weightedLodSize scaling and consider an upper clamp

The new metric sqrt(sx^2 + 0.5 * sy^2 + sz^2) with a global factor of 180 can yield very large maxLod values for big props, since only trees are clamped to 640 later. This may push far-LOD visibility to extreme distances and impact performance.

Consider either:

  • adding a global upper bound for maxLod (similar to trees), or
  • documenting why unbounded maxLod is acceptable for non-tree props.

134-142: Factor-based distribution is now strictly linear; ensure this matches the desired bias toward higher-detail LODs

The new per-level formula:

local factor = (n / levels)
local LODCutoff = factor * maxLod
data.LODCutoff = MathFloor((LODCutoff + 5) / 10) * 10

produces evenly spaced cutoffs (linear in n) with rounding to the nearest 10. Earlier discussions in the PR referenced higher-order factors to keep high-detail LODs visible longer.

If the design goal is still to favor higher-detail LODs (slower drop-off of detail), consider whether a non-linear factor (e.g., (n / levels)^k with k > 1 or a small offset) would align better with the intended visual behavior, or add a short comment documenting why linear spacing is now preferred.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6d2bf4b and 884e37c.

📒 Files selected for processing (1)
  • lua/system/blueprints-props.lua (1 hunks)

@Basilisk3
Copy link
Collaborator Author

Basilisk3 commented Nov 28, 2025

This way you can spot broken tree groups because the individual trees render with lod2 on medium zoom ranges.

While this is a good idea in principle, I don't think it's necessary, as you can spot broken tree groups already.

Below is the current state of the PR. As you can see, the LOD levels are now inconsistent depending on where you center the camera (see the top left). Additionally, I think keeping the second LOD level in place looks nicer overall, as shown here. This is because the colors of the first and last LOD levels look quite different, and the second LOD level helps ease the transition.
Trees

@Basilisk3
Copy link
Collaborator Author

@BlackYps If you want, you can ping me on Discord and I will try to reply as soon as I can. These AI comments are making this pretty convoluted.

@FAForever FAForever deleted a comment from coderabbitai bot Nov 28, 2025
@Garanas
Copy link
Member

Garanas commented Nov 28, 2025

I changed the function so it now allows setting explicit values for tree groups and single trees. The tree groups only use lod1 and lod3. This way you can spot broken tree groups because the individual trees render with lod2 on medium zoom ranges. Tested on selkie and the fa and faf props test map. I believe this should solve the problem of not being able to spot broken tree groups.

Unrelated to the tree changes: big props are now visible for longer.

I don't think it was mentioned in this thread but the breaking of tree groups updates through the fog of war. Have you checked whether this makes it (too) obvious to spot raids through the fog of war at certain camera angles?

As an example, take this forum post:

The problem will always be there of course. But before the aim was to minimize it, which was accomplished by having individual trees and tree groups always share the same lod settings.

prop.Display.Mesh.LODs[2].LODCutoff = 200
prop.Display.Mesh.LODs[3].LODCutoff = 640
return
elseif (prop.ScriptClass == 'TreeGroup' and TableGetn(prop.Display.Mesh.LODs) == 3) then
Copy link
Member

@Garanas Garanas Nov 28, 2025

Choose a reason for hiding this comment

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

The use of elseif after a return statement is confusing. It gives the impression that the function can continue. The return will already make you exit the function.

It's better to just write:

if (...) then

   (...)

   return
end

if (...) then

   (...)

   return
end

-- default case when no special rules apply

(...)

@BlackYps
Copy link
Contributor

I investigated some more and I am now convinced that my idea to show a different lod for groups and single trees is based on a misunderstanding when I was discussing the issue with Rhaelya. We were convinced that the visible difference between both was because of different lods being visible. But I think we were wrong. It's hard to get a good understanding of what lod level exactly you are seeing when zooming around in a map. I did some tests and found that there are minute differences in color in the lod3 of groups and single trees. So there is no reason to set different lod values for both. I will remove that piece of code again.

Copy link

@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: 0

♻️ Duplicate comments (1)
lua/system/blueprints-props.lua (1)

112-119: LOD scaling and rounding logic look sound; remember to re‑bake blueprints.

Using a diagonal-like size metric to derive maxLod and spacing cutoffs linearly by n / levels gives monotonic, size-aware LOD distances, and rounding with MathFloor((LODCutoff + 5) / 10) * 10 cleanly snaps to the nearest 10 while preserving ordering. Since ProcessLOD is also called from BakePropBlueprints, merging this will change baked LODCutoff values across all props, so ensure the bake-blueprints workflow is triggered once the final formula is settled.

Also applies to: 132-139

🧹 Nitpick comments (1)
lua/system/blueprints-props.lua (1)

120-130: Clarify Tree/TreeGroup special-case control flow and reuse levels.

Functionally this branch is fine (3‑LOD trees get the explicit [40, 180, 640] distances, others are capped via maxLod = 640), but the nested if plus calling TableGetn again later makes the flow a bit harder to follow. Consider hoisting local levels = TableGetn(prop.Display.Mesh.LODs) once and structuring it as sequential guards (if isTree and levels == 3 then ... return end / if isTree then maxLod = 640 end) so the early-return and fallback are more obvious.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 884e37c and 34d08b1.

📒 Files selected for processing (1)
  • lua/system/blueprints-props.lua (1 hunks)

Copy link

@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

🧹 Nitpick comments (1)
lua/system/blueprints-props.lua (1)

112-118: Document the weighted size formula and the 200 multiplier.

The diagonal-based weightedLodSize formula aligns with the recommendation to move toward a length-based measure, and reducing the Y-axis weight (0.5 coefficient) is reasonable given typical camera angles. However, the rationale for the specific formula and the 200 multiplier should be documented inline to help future maintainers understand the tuning choices.

Consider adding a comment:

 local sx = prop.SizeX or 1
 local sy = prop.SizeY or 1
 local sz = prop.SizeZ or 1

-        -- give more emphasis to the x / z value as that is easier to see in the average camera angle
+        -- Compute a weighted diagonal size; Y (height) has reduced weight (0.5) 
+        -- because it's less prominent from typical camera angles
         local weightedLodSize = MathSqrt(sx * sx + 0.5 * sy * sy + sz * sz)
+        -- Scale to maximum LOD distance; 200 multiplier tuned for visual quality vs. performance
         local maxLod = 200 * weightedLodSize
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34d08b1 and 9dbddc3.

📒 Files selected for processing (1)
  • lua/system/blueprints-props.lua (1 hunks)
🔇 Additional comments (1)
lua/system/blueprints-props.lua (1)

131-138: Verify that the linear LOD factor matches the intended formula.

The current implementation uses a simple linear factor (n / levels) with no polynomial exponent or flat offset:

local factor = (n / levels)
local LODCutoff = factor * maxLod

However, the PR discussion and past review comments reference testing with higher-power exponents (e.g., (k/n)^3 or (k/n)^4) and adding flat offsets (e.g., +30) to bias toward higher-detail LODs and prevent small cutoff values. The current linear formula produces a different progression than those approaches.

Positive: The rounding change from "always round up" to "round to nearest 10" (line 138) is an improvement that produces more accurate cutoff values.

Please confirm whether:

  1. The linear formula is the final intended design after testing various exponents, or
  2. The polynomial exponent and offset were accidentally omitted during recent changes.

If the linear formula is intentional, consider adding a comment explaining that decision (e.g., "Linear progression chosen after testing for smoother LOD transitions").

Copy link
Collaborator Author

@Basilisk3 Basilisk3 left a comment

Choose a reason for hiding this comment

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

Apart from that lgtm.

@Basilisk3
Copy link
Collaborator Author

This is not related to any changes in the PR, but another thing I noticed while playing, is that tree groups sometimes have difficulties rendering when terrain is uneven.

Trees 2

Trees 3

Visible when comparing the bottom center tree groups. This only appears at certain zoom levels.

@BlackYps
Copy link
Contributor

BlackYps commented Dec 1, 2025

That's probably because of the terrain tesselation and unavoidable

Copy link

@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: 0

Caution

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

⚠️ Outside diff range comments (1)
lua/system/blueprints-props.lua (1)

63-74: Bug: isReclaimable check is broken, warning can never trigger

This isn’t part of the new changes, but it’s a correctness issue:

local isObstructing = TableFind(prop.Categories, 'OBSTRUCTSBUILDING')
local isReclaimable = TableFind(prop.Categories, 'OBSTRUCTSBUILDING')
...
if not (prop.ScriptClass == "Tree" or prop.ScriptClass == "TreeGroup") and isReclaimable then
    if prop.Economy and prop.Economy.ReclaimMassMax and prop.Economy.ReclaimMassMax > 0 and
        not isObstructing then
        if not isObstructing then
            WARN("Prop is missing 'OBSTRUCTSBUILDING' category: " .. prop.BlueprintId)
        end
    end
end

Because isReclaimable and isObstructing both search for 'OBSTRUCTSBUILDING', the condition effectively becomes isObstructing and not isObstructing, which is impossible, so the warning never fires.

If the intent was to check for a separate “reclaimable” category, this should likely be:

-    local isObstructing = TableFind(prop.Categories, 'OBSTRUCTSBUILDING')
-    local isReclaimable = TableFind(prop.Categories, 'OBSTRUCTSBUILDING')
+    local isObstructing = TableFind(prop.Categories, 'OBSTRUCTSBUILDING')
+    local isReclaimable = TableFind(prop.Categories, 'RECLAIMABLE')

Please adjust to the correct category name used elsewhere in the codebase so that missing OBSTRUCTSBUILDING flags on reclaimable, non-tree props are actually reported.

🧹 Nitpick comments (1)
lua/system/blueprints-props.lua (1)

120-129: Tree special-case: constant cutoffs and formatting

Semantically this branch does what it says: for Tree / TreeGroup with exactly 3 LODs you enforce [40, 165, 640] and exit early; all other trees reuse the formula but clamp maxLod to 640. That’s reasonable, but:

  • All 3‑LOD trees now share identical cutoffs regardless of actual size, ignoring weightedLodSize. If your tree assets vary significantly in scale, consider at least documenting why a fixed set is preferred over size-based scaling, or reuse weightedLodSize to derive these values.
  • The if (...) and then split across lines (Lines 120–121) is legal Lua but non-idiomatic and was already called out by reviewers. Putting then on the same line as the if would improve readability and match the rest of the file.

Example formatting tweak:

-        if (prop.ScriptClass == 'Tree' or prop.ScriptClass == 'TreeGroup')
-          then
+        if (prop.ScriptClass == 'Tree' or prop.ScriptClass == 'TreeGroup') then
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9dbddc3 and 03e94f3.

📒 Files selected for processing (1)
  • lua/system/blueprints-props.lua (1 hunks)
🔇 Additional comments (2)
lua/system/blueprints-props.lua (2)

112-119: Size-weighted LOD metric and maxLod computation look sound

Using MathSqrt(sx * sx + 0.5 * sy * sy + sz * sz) to derive weightedLodSize and basing maxLod on that (Line 118) gives a diagonal/length-like measure with reduced Y influence and should behave well across varying prop dimensions. The math is correct and avoids pathological cases thanks to the or 1 defaults on sizes.


131-139: Per-level LOD distribution and rounding behavior are consistent

The linear (n / levels) * maxLod factor combined with MathFloor((LODCutoff + 5) / 10) * 10 correctly spaces LODs between 0 and maxLod and rounds to the nearest 10 units for positive distances. This is clear, easy to tune via maxLod, and avoids the off‑by‑one behavior of “always round up” schemes.

@BlackYps
Copy link
Contributor

BlackYps commented Dec 7, 2025

Looks good to me now

@Basilisk3
Copy link
Collaborator Author

The mass and hydrocarbon deposit props now only appear at very low zoom levels. Apart from that, I think the PR is ready.

@BlackYps
Copy link
Contributor

Has this not always been the case?

@Basilisk3
Copy link
Collaborator Author

Yes, but not to this extent.

@BlackYps
Copy link
Contributor

Found the issue. massDeposit01_prop.bp defines:

    SizeX = 0.1,
    SizeY = 0.1,
    SizeZ = 0.1,

Same for the hydro markers. Do we expect any side effects when increasing these values?

@Garanas
Copy link
Member

Garanas commented Dec 15, 2025

These values are used for collision detection. For splash damage, for example. But the deposit props are immune to damage. I don't think there are significant side effects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: baking of blueprints related to baking properties into blueprints via workflows area: graphics Anything Related to the Game Graphics

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants