feat: derive resource visuals from state
This commit is contained in:
@@ -787,16 +787,19 @@ Completed:
|
||||
separate terrain-snapped approach points. Matched captures and a focused
|
||||
scenario prove three-batch visual cost, nested discovery, and a forced
|
||||
query beyond the first 24 m range without changing the 18-resource state.
|
||||
38. `Jajce Resource States 05`: a shared amount-derived presentation contract
|
||||
now gives that berry and tree honest full, low, and depleted states. Real
|
||||
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.
|
||||
|
||||
Next:
|
||||
|
||||
1. Give the authored berry/tree resources state-driven low/depleted visuals
|
||||
sourced from their real `ResourceStateRecord` amount. Prove NPC and player
|
||||
extraction plus save/restore rebuild the same presentation without adding
|
||||
visual fields to simulation state.
|
||||
2. Apply the workflow to a second forest-edge consumer only after that contract
|
||||
is honest and reusable. Add livestock only with a real identity and
|
||||
interaction contract.
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
@@ -904,17 +904,29 @@ of eighteen resources, sit above the carved channel, and expose separate
|
||||
terrain-snapped approach points. A forced village query expands beyond the
|
||||
initial 24 m range and selects the nested berry exactly by ID.
|
||||
|
||||
The immediate next slice should make those two resource-specific visuals
|
||||
reflect authoritative amount/depletion: thin the berry patch and leave a stump
|
||||
or equivalent readable tree state after real NPC/player extraction, then prove
|
||||
save/restore rebuilds the same presentation without persisting visual-only
|
||||
state. Only after both the berry and tree consume that contract should shared
|
||||
cluster/depletion tooling be extracted or the workflow copied to a forest
|
||||
edge. Do not generalize the resource grid to people/buildings/events or
|
||||
introduce active/abstract LOD before those consumers need it.
|
||||
The first amount-derived resource presentation slice is complete. A shared
|
||||
`ResourceAmountVisual` contract reads the loaded `ResourceNode`'s authoritative
|
||||
amount and derives full, low, or depleted presentation without entering saved
|
||||
state. Real player berry harvests remove fruit and leaf mass; real NPC wood
|
||||
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.
|
||||
|
||||
Recently completed:
|
||||
|
||||
- `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
|
||||
states without visual save fields, and matched Metal frames record the berry
|
||||
thinning, sparse crown, fruitless remnant, and stump.
|
||||
- `Jajce Resource Grove 04`: two existing river resources now live as nested
|
||||
stable-ID anchors inside a restrained decorative bank cluster. Twenty-eight
|
||||
understory instances use three MultiMesh batches, bespoke berry/tree visuals
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# Jajce Resource States 05
|
||||
|
||||
Captured: 2026-07-17
|
||||
|
||||
## Files
|
||||
|
||||
- [full resources](jajce_resource_states_05_full.png)
|
||||
- [low resources](jajce_resource_states_05_low.png)
|
||||
- [depleted resources](jajce_resource_states_05_depleted.png)
|
||||
- `world/resource_nodes/ResourceAmountVisual.gd`
|
||||
- `world/jajce/HarvestableTreePresentation.tscn`
|
||||
- `tests/jajce_resource_presentation_state_test.gd`
|
||||
|
||||
The three images use the same 1280×720 cross-river camera, daylight value,
|
||||
warmup, and Metal renderer. Debug labels are hidden. The lower-left berry patch
|
||||
and right-hand harvestable tree are shown at their authored full amounts, at
|
||||
40%/50% respectively, and at zero.
|
||||
|
||||
## Amount-derived visual language
|
||||
|
||||
`ResourceAmountVisual` finds its owning `ResourceNode` and derives one of three
|
||||
tiers from `amount_remaining / initial_amount`:
|
||||
|
||||
- full keeps all five berry leaf clumps, eight berries, and four tree canopies;
|
||||
- low keeps three leaf clumps, four berries, and two tree canopies; and
|
||||
- depleted keeps a two-leaf fruitless remnant and replaces the tree with a
|
||||
low-poly stump and warm cut face.
|
||||
|
||||
The threshold is deliberately simple and readable: a positive source at or
|
||||
below half amount is low. The berry keeps using two bounded MultiMeshes, so
|
||||
thinning changes only `visible_instance_count`; it does not create or destroy
|
||||
nodes during play. The tree wrapper reuses the existing wind-reactive standing
|
||||
tree and toggles authored crown/stump parts.
|
||||
|
||||
## Authority and restore proof
|
||||
|
||||
`ResourceStateRecord` remains the only amount authority. `ResourceNode` now
|
||||
emits its existing `amount_changed` presentation signal when authoritative
|
||||
state is rebound, including restore. The visual contract listens to that signal
|
||||
and also refreshes once after scene readiness, covering either bind order.
|
||||
|
||||
The focused scenario performs two real player harvests on
|
||||
`berry_bush_river_02` and two real NPC gather completions on
|
||||
`tree_river_resource_01`, checks the low presentation and NPC wood inventory,
|
||||
then fully depletes both through those same production paths. It restores low
|
||||
and depleted snapshots in turn and verifies the presentation is reconstructed.
|
||||
The resource records contain no visual, visibility, tier, or stump fields.
|
||||
|
||||
The capture tool's optional amount overrides also construct and bind ordinary
|
||||
`ResourceStateRecord`s. They do not directly manipulate visual children, so
|
||||
the review images exercise the same runtime contract as gameplay.
|
||||
|
||||
## Next slice
|
||||
|
||||
Apply this contract to the existing `tree_forest_grove_01` and
|
||||
`tree_forest_grove_02` stable IDs in one bounded forest-edge cluster. Decorative
|
||||
canopy and understory should stay presentation-only while the two finite trees
|
||||
remain reachable, discoverable, depletable, and restore correctly.
|
||||
|
||||
## 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/JajceResourceStateLookdev.tscn \
|
||||
--output=res://docs/baselines/jajce_resource_states_05_full.png \
|
||||
--hide-resource-labels
|
||||
```
|
||||
|
||||
For the low frame, append:
|
||||
|
||||
```text
|
||||
--resource-amount=berry_bush_river_02:2
|
||||
--resource-amount=tree_river_resource_01:4
|
||||
```
|
||||
|
||||
For the depleted frame, use the same arguments with both amounts set to `0`.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 429 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cnusf1uofgeam"
|
||||
path="res://.godot/imported/jajce_resource_states_05_depleted.png-4da1f8d2357fb72267bc5e3167868d55.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/baselines/jajce_resource_states_05_depleted.png"
|
||||
dest_files=["res://.godot/imported/jajce_resource_states_05_depleted.png-4da1f8d2357fb72267bc5e3167868d55.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: 430 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c6fr86t0glm1p"
|
||||
path="res://.godot/imported/jajce_resource_states_05_full.png-b7555dd39fe62146f66c1e731a0813d3.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/baselines/jajce_resource_states_05_full.png"
|
||||
dest_files=["res://.godot/imported/jajce_resource_states_05_full.png-b7555dd39fe62146f66c1e731a0813d3.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: 428 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://lerebtc2de5v"
|
||||
path="res://.godot/imported/jajce_resource_states_05_low.png-ca9e13189ad1a8dc22e32380ddf38b2f.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://docs/baselines/jajce_resource_states_05_low.png"
|
||||
dest_files=["res://.godot/imported/jajce_resource_states_05_low.png-ca9e13189ad1a8dc22e32380ddf38b2f.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
|
||||
Reference in New Issue
Block a user