Skip to content

Forest previews for baked terrain

Unvisited TDL terrain carries a separate forest layer. The near preview replays surface schematic decorations using the game's placement rules, biome palette, world seed, rotations and schematic voxels. Ground and tree roots share tdl_column.lua with the mapgen. This reads the bake without emerging or writing mapblocks.

The geometric preview uses the same 1, 2, 4 progression as the retained voxel renderer. Its horizontal distance bands are:

Tree cell Terrain sample Outer reach (nodes)
1 4 512
2 8 1,024
4 16 2,048
Statistical canopy 64 4,096
Statistical canopy 128 Server/client horizon

These reaches are capped by the negotiated horizon. With detailed server data available, retained world geometry uses the same bands as a minimum quality; projected-size tiers can keep it finer. The extra eight-node terrain rung avoids the previous four-to-sixteen jump. Overview tiles load first; geometric refinement proceeds near to far across the three forest rungs. Cold geometric coverage can still take minutes in a large dense forest; the canopy approximation remains visible during refinement.

Chunk caches retain all three tree reductions. The mesher removes interior faces between vertical runs, including mixed-resolution neighbours, and merges coplanar rectangles without filling crown openings. Coarse samples carry foliage material, crown height and coverage from the game's schematic/density definitions. They are floating crowns above independently rendered ground, rather than solid columns from the ground to the canopy.

Actual summaries discover available mapblocks, then a separate detailed stream supplies their nodes for the one- and two-node rungs. Coarse four-node summaries remain discovery data while a finer preview is visible. The client builds the same compact voxel boundaries used by retained world geometry, preserving trunks, crown openings, node colours and lighting.

Published world geometry removes its corresponding prediction. Synthetic ground summaries only replace the ground and cannot erase the forest. Provider revisions invalidate synthetic server summaries while retaining summaries of actual world data. Prediction removal is three-dimensional: a ground block cannot erase a crown above it, and a known empty block can remove a chopped tree. Replacement meshes become visible in the same publication as the preview mask. The mask uses immutable published inputs and the actual ground resolution, including one-node ledges. LOD ground coverage comes from emitted top faces. A buried block or a column ceded to another tier cannot claim coverage merely because its occupancy chain contains ground; that previously opened permanent sky gaps at the boundary.

TDL recalculates lighting after placing decorations. This fixes zero-light leaves in newly generated chunks; existing chunks retain their saved lighting until the server recalculates it (for example with its fixlight command).

Revision identities include the bake, settings, biome/decorations, schematic files and preview/mapgen source.

The prediction currently covers schematic trees with leaf/tree node groups; L-system trees and arbitrary mapgen callbacks are not reproduced. Exterior placement skips cave floors. Probabilistic schematic nodes use a deterministic preview RNG rather than the engine's global schematic RNG, so individual random leaves can differ when generated terrain replaces the prediction.

Transport

surface_tiles=2 adds compressed forest runs to surface tiles; version-one requests still receive their original terrain-only layout. Supported sample steps are 4, 8, 16, 64 and 128. The v2 decoded payload starts with the original 256 seven-byte terrain samples, followed by twelve-byte forest records:

Field Encoding
Local X, Z Two big-endian unsigned 16-bit integers
Bottom Y, exclusive top Y Two big-endian signed 16-bit integers
Material palette index, param2 One byte each
Horizontal cell size, coverage One byte each

The payload is deflate-compressed and base64-encoded after the shared material palette. Dense tiles use surface_part messages of at most 60,000 body bytes; the client assembles only requested revision/key pairs, with bounded part counts and memory, before publishing a complete tile. Geometry is never coarsened to fit a packet. The client also bounds decoded sizes, coordinates, material indices and cell sizes. Server work yields cooperatively against a two-millisecond tick budget, with bounded pending requests and caches.

far_fine=1 advertises the detailed block stream. Requests contain a version, request token and mapblock position. Replies carry a name palette and compressed runs of node count, palette index, param1 and param2. Unknown blocks are explicitly unavailable, distinct from 4,096 known air nodes. Reads never generate terrain. Queues, wire sizes, decompression, coordinates and the negotiated range are bounded. Dig/place notifications trigger refreshes; polling also observes bulk/ABM edits. Identical replies do not rebuild geometry. Near meshes take precedence over remote replies, and a newer live block revision invalidates an outstanding read. Retained blocks outside the near field also refresh: having an old block in memory does not make it current server data.

Verification

  • build/goanna_surface_test: protocol validation, signed coordinates, bounded decompression, partial terrain refinement, crown openings, separate canopy volume, actual fine-block decoding, known-empty crown removal, fine ground coverage and synthetic-ground versus actual-world handoff.
  • build/goanna_lod_test: projected-size voxel tiers, compact one-node ground, tree outlines and mixed-resolution face culling.
  • luajit tools/test/test-fine-server.lua: actual voxel runs, light/colour preservation, unavailable versus empty replies, grant bounds and edit invalidation.
  • luajit tools/test/test-forest-preview.lua: placement/rotation parity on a flat world, biome exclusion, asymmetric schematic outlines and 1/2/4 reductions.
  • luajit tools/test/test-tdl-columns.lua: 2,304 point-sampled roots agree with batched mapgen across dry, shore and channel cases. An optional previous mapgen file also compares the complete generated node arrays; the extraction passed this comparison against the pre-change implementation.
  • luajit tools/test/test-surface-server.lua: grants, versions, bounded cooperative work, cold/warm caching and backward compatibility.
  • res://tests/local_server_terrain_diffusion.gd: deployment includes every TDL and Goanna Lua module.

tools/test/forest-review/run.py creates an isolated Mineclonia world from an existing bake. It records loading stats and screenshots without visiting the user's world. The September 15 review used a cherry grove, seed 1234, a 1,024-node horizon and 1280×720 on an RTX 3090, without PBR. One complete 545-tile run reported about 156 fps. This is a spot measurement, not a general performance guarantee. The cache-migration run replaced 500 old summary areas with revision-tagged entries and retained detailed distant crowns without the bare ground-only ring.