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
+12 -5
View File
@@ -792,14 +792,21 @@ Completed:
player berry harvests thin fruit and leaves; real NPC wood gathers thin the
crown and leave a stump. Low and depleted saves restore the same visuals
using only `amount_remaining`, with matched Metal comparison frames.
39. `Jajce Forest Edge 06`: `tree_forest_grove_01` and
`tree_forest_grove_02` now anchor a bounded forest-edge cluster beyond the
first 24 m discovery pass. Two decorative trees plus 24 fern, mushroom, and
stone instances stay presentation-only. Both finite trees remain reachable,
deplete into shared stumps, restore from authoritative amount, and keep the
world/save total at eighteen resources.
Next:
1. Move the existing `tree_forest_grove_01` and `tree_forest_grove_02` anchors
into one bounded forest-edge authoring cluster. Reuse the proven tree amount
presentation, preserve both stable IDs, and prove reachable expanding
discovery plus depletion/restore without serializing decorative foliage.
2. Add livestock only with a real identity and interaction contract.
1. Add one named goat as an identity-backed simulation vertical slice: stable
animal ID, authoritative position and hunger/feed state, loaded visual
binding, and an exact feed interaction shared by one NPC and the player.
Feeding must withdraw real pantry food and survive deterministic save/load.
2. Add a small herd, breeding, or animal products only after that single-animal
identity and conservation contract is proven.
Do not start with GIS data, a full city, a large asset pack, or more NPC
mechanics. The next proof is a beautiful stage for the systems that already
+24 -7
View File
@@ -912,16 +912,33 @@ gathers thin the crown and ultimately leave a warm-cut stump. Restoring both
low and depleted snapshots rebinds the same nodes and reconstructs the same
visuals from `ResourceStateRecord.amount_remaining` alone.
The immediate next slice should apply that proven contract to the existing
`tree_forest_grove_01` and `tree_forest_grove_02` anchors as one bounded
forest-edge authoring consumer. Preserve both stable IDs, keep decorative
canopy/understory outside simulation state, and prove reachable expanding
discovery plus depletion/restore with the shared tree presentation. Do not
generalize the resource grid to people/buildings/events or introduce
active/abstract LOD before those consumers need it.
The second authored foliage/resource workflow is complete. The existing
`tree_forest_grove_01` and `tree_forest_grove_02` anchors now form one bounded
forest edge with two decorative silhouette trees and 24 fern, mushroom, and
stone instances in three MultiMesh batches. Both stable IDs and definitions
remain authoritative, while village-facing interaction points sit beyond the
initial 24 m discovery radius and remain reachable on the Terrain3D-derived
navigation mesh. Real NPC depletion leaves the shared stump and restore
rebuilds the sparse standing tree from amount alone. The river and forest
clusters now share only the terrain-snap, bounded-instance, and anchor-layout
code proven by those two consumers.
The immediate next slice should introduce livestock only through one
identity-backed animal vertical slice: one named goat with a stable animal ID,
simulation-owned position and hunger/feed state, a loaded presentation binding,
and one exact feed interaction available to both an NPC and the player. Feeding
must consume real pantry food and save/restore deterministically. Do not make
the animal a `ResourceNode`, add a herd, breeding, products, or a generalized
animal spatial index before that first identity and conservation contract is
honest.
Recently completed:
- `Jajce Forest Edge 06`: two existing deep-forest tree IDs now anchor a
restrained four-tree silhouette with 24 decorative understory instances.
Both targets require expanded loaded-resource discovery, remain reachable,
reuse amount-driven crowns/stumps, and preserve the eighteen-resource save
contract through real NPC depletion and restore.
- `Jajce Resource States 05`: the authored river berry/tree now derive full,
low, and depleted visuals from authoritative amounts. Player and NPC
extraction drive the changes, save/restore reconstructs low and depleted
+9 -8
View File
@@ -982,14 +982,15 @@ Raw samples and workload exclusions live in
[Simulation scaling baseline 02](benchmarks/SIMULATION_SCALING_BASELINE_02.md)
and [Loaded Resource Discovery 01](benchmarks/LOADED_RESOURCE_DISCOVERY_01.md).
The authored Jajce watercourse, navigation rebake, and first bounded
foliage/resource placement proof are complete. The next slice should derive
low/depleted berry and tree visuals from authoritative resource amount, cover
real NPC/player extraction and save/restore reconstruction, and keep that
presentation out of serialized simulation state. Apply the cluster workflow to
a second forest edge only after the depletion contract supplies a real second
consumer. Do not yet generalize the resource grid or introduce active/abstract
simulation LOD.
The authored Jajce watercourse, navigation rebake, amount-derived resource
visuals, and two bounded foliage/resource placement proofs are complete. The
riverbank and forest edge preserve stable finite-resource IDs, separate
decorative density from simulation authority, support discovery beyond the
first 24 m range, and reconstruct sparse/depleted visuals from authoritative
amount. The next slice should introduce one named goat only through a stable
simulation identity, authoritative position and feed state, loaded visual
binding, exact NPC/player feeding cost, and deterministic save/restore. Do not
yet generalize the resource grid or introduce active/abstract simulation LOD.
The remaining simulation-garden target still aims for:
+9
View File
@@ -577,6 +577,15 @@ selects the farther berry only after expanding beyond the first 24 m range.
The matched review lives in
[Jajce Resource Grove 04](baselines/JAJCE_RESOURCE_GROVE_04.md).
Amount-derived berry/tree presentation and the second placement consumer are
also complete. `ResourceAmountVisual` reconstructs full, low, and depleted
states from authoritative amount without adding save fields. The existing
`tree_forest_grove_01` and `tree_forest_grove_02` records now sit inside one
bounded forest-edge cluster with reachable interaction points beyond 24 m;
forced resolution expands to the stable ID, and real NPC depletion/restore
reuses the same crown/stump contract. The matched review lives in
[Jajce Forest Edge 06](baselines/JAJCE_FOREST_EDGE_06.md).
## Test scenarios
At minimum, exercise:
+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