feat: author discoverable forest edge

This commit is contained in:
Rijad Zuzo
2026-07-18 19:09:04 +02:00
parent 2719b0398b
commit 1f09ebe6b6
21 changed files with 911 additions and 180 deletions
+98
View File
@@ -0,0 +1,98 @@
# Jajce Forest Edge 06
Captured: 2026-07-18
## Files
- [before forest edge](jajce_forest_edge_06_before.png)
- [authored forest edge](jajce_forest_edge_06_after.png)
- [finite trees depleted](jajce_forest_edge_06_depleted.png)
- `world/jajce/ForestEdgeResourceCluster.tscn`
- `world/jajce/TerrainResourceCluster.gd`
- `tests/jajce_forest_edge_cluster_test.gd`
The images use the same 1280×720 camera, fixed daylight value, warmup, and
Metal renderer. Debug labels are hidden. The before frame shows two generic
resource boxes below disconnected south-edge trees. The authored frame uses
the same finite IDs as the two central harvestable trees; the depleted frame
shows those two as stumps while the decorative forest silhouette remains.
## Visual reduction
The forest edge contains:
- 10 low-poly fern clumps;
- 8 oversized cream-stem, warm-cap mushrooms;
- 6 flattened forest stones;
- 2 decorative deciduous silhouette trees; and
- 2 finite harvestable trees with amount-derived crowns and stumps.
The 24 understory details use three `MultiMeshInstance3D` batches. The two
existing south-edge conifers remain outside the cluster and frame it at a
larger scale. This keeps the grove legible from the village without turning the
whole terrain into dense foliage.
## Authority and shared authoring contract
`ResourceAnchors` contains only `tree_forest_grove_01` and
`tree_forest_grove_02`, preserving their definitions and the existing total of
eighteen finite resources. `DecorativeInstances` contains no `ResourceNode`
descendants and never enters saves, reservations, checksums, or conservation.
The riverbank and forest edge are now the two concrete consumers of
`TerrainResourceCluster`. That small shared base owns only their proven scene
contract: terrain snapping for authored trees and interaction points, bounded
MultiMesh placement, fern mesh construction, resource-anchor enumeration, and
presentation statistics. Resource-specific palettes, offsets, and meshes stay
in each cluster.
Both finite trees reuse `HarvestableTreePresentation`. Depletion therefore
removes only the authoritative standing trees; the two decorative trees and
surrounding conifers remain, giving the living world an honest but not barren
silhouette.
## Discovery, navigation, and restore proof
The trees moved roughly five metres deeper into the forest edge. Their
village-facing interaction points are approximately 26.5 m and 26.2 m from the
village origin, beyond the adapter's initial 24 m query. The focused scenario
confirms both IDs appear only in the farther query, disables every other wood
source, and resolves `tree_forest_grove_01` after more than one range pass.
The same scenario asks the project-owned navigation map for real paths to both
interaction points, verifies each endpoint is reached, and checks every route
point against Terrain3D height. No terrain or navigation rebake was needed.
Finally, the test leaves the first tree at one configured yield, saves that low
state, and completes a real reserved NPC gather. The exact yield enters NPC
inventory and the tree becomes a stump. Restoring the snapshot rebinds the
same stable ID and reconstructs the sparse standing crown from authoritative
amount alone.
## Next slice
Introduce one named goat as an identity-backed simulation entity rather than a
resource prop. Its stable ID, position, and hunger/feed state should be saved;
one NPC and the player should share an exact feed interaction that withdraws
real pantry food. A herd, breeding, products, and animal spatial indexing stay
deferred until that contract is proven.
## Capture commands
```bash
HOME="$PWD/logs/quality/godot_profile" \
APPDATA="$PWD/logs/quality/godot_profile" \
LOCALAPPDATA="$PWD/logs/quality/godot_profile" \
/Applications/Godot.app/Contents/MacOS/Godot \
--path "$PWD" --script res://tools/capture_jajce_lookdev.gd -- \
--scene=res://world/jajce/JajceForestEdgeLookdev.tscn \
--output=res://docs/baselines/jajce_forest_edge_06_after.png \
--hide-resource-labels
```
For the depleted frame, append:
```text
--resource-amount=tree_forest_grove_01:0
--resource-amount=tree_forest_grove_02:0
```
Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://4tlahsqubofd"
path="res://.godot/imported/jajce_forest_edge_06_after.png-cc336e5231ac96e8d23247a881a0ec1c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/baselines/jajce_forest_edge_06_after.png"
dest_files=["res://.godot/imported/jajce_forest_edge_06_after.png-cc336e5231ac96e8d23247a881a0ec1c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://gsie1efiik5"
path="res://.godot/imported/jajce_forest_edge_06_before.png-ecb42151d9a8db85404cc1153afa0bcf.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/baselines/jajce_forest_edge_06_before.png"
dest_files=["res://.godot/imported/jajce_forest_edge_06_before.png-ecb42151d9a8db85404cc1153afa0bcf.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dnu1owrmly7wf"
path="res://.godot/imported/jajce_forest_edge_06_depleted.png-08c916e5b04639615251b670dcd41f56.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://docs/baselines/jajce_forest_edge_06_depleted.png"
dest_files=["res://.godot/imported/jajce_forest_edge_06_depleted.png-08c916e5b04639615251b670dcd41f56.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1