Expand voxel gameplay, lighting, full-height streaming and world imports
MVP checks / mvp (push) Canceled after 0s
MVP checks / mvp (push) Canceled after 0s
Add shared Rust/WASM physics, worker meshing and diagnostics, 64-chunk full-height streaming, atlas texture support, and baseline world import. Document the current implementation and include the supplied in-game lobby screenshot.
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
# Block and sky lighting
|
||||
|
||||
Light-emitting block states illuminate their surroundings. The renderer computes
|
||||
two independent integer fields, **block light** and **sky light**, each ranging
|
||||
from 0 to 15. These fields determine the brightness of terrain, transparent
|
||||
surfaces and moving avatars/entities. Emissive surfaces themselves remain bright.
|
||||
|
||||
## Rules and reference data
|
||||
|
||||
Emission comes from the server catalog's state-specific `light` value. An ordinary
|
||||
torch emits 14, a sea lantern 15, and an unlit lamp emits 0. State changes,
|
||||
installation and removal trigger a new calculation. Overlapping lights select
|
||||
the strongest level; they do not add their levels together.
|
||||
|
||||
Block light travels to the six adjacent cells and loses at least one level at
|
||||
each transition. Target material dampening and the combined source/target
|
||||
occlusion faces can reduce or stop transmission. The solver uses actual face
|
||||
rectangle unions, including complementary slab and stair shapes, rather than
|
||||
treating every collision box as an opaque cube. Light can travel around an open
|
||||
doorway with attenuation along that path.
|
||||
|
||||
Open vertical sky has level 15. Unobstructed downward travel through clear cells
|
||||
keeps 15; other propagation loses at least one level. Roofs, material dampening
|
||||
and face occlusion interrupt direct skylight. A sealed room therefore has sky
|
||||
level 0 even during the daytime scene, while a light source inside it
|
||||
continues to illuminate the room.
|
||||
|
||||
`client/light-properties.json` contains measured Java 26.2 dampening and effective
|
||||
light-occlusion shapes for all **32,366 states**, with 60 deduplicated shapes.
|
||||
The loader resolves either the catalog's `minecraft_id` or state strings,
|
||||
including partial properties with original defaults. These IDs are independent
|
||||
of Shacraft's runtime material IDs. Examples include transparent glass (0),
|
||||
tinted glass (15), water/leaves/ordinary ice (1), and packed/blue ice (15).
|
||||
Metadata is about light transmission, which can differ from collision geometry.
|
||||
|
||||
The data and 78 directional crossing measurements come from the pinned original
|
||||
executable through an independently authored probe. The propagation tests agree
|
||||
with those crossings. This is evidence for the measured properties and local
|
||||
transitions, not execution of an entire original Minecraft world-light engine.
|
||||
|
||||
```sh
|
||||
python3 scripts/measure_lighting.py --java /path/to/java25/bin/java
|
||||
node --test client/tests/light-properties.test.js client/tests/block-light.test.js
|
||||
```
|
||||
|
||||
The probe checks the official bundle and extracted executable hashes. No original
|
||||
runtime or proprietary source code is distributed. The compact runtime metadata
|
||||
is about 150 KB before HTTP compression.
|
||||
|
||||
## Rendering and updates
|
||||
|
||||
`terrain-controller.js` maintains one persistent `terrain-worker.js` instance.
|
||||
The worker owns the section-indexed block map, material light properties, texture
|
||||
metadata and bounded light fields. A normal streamed view has 196,608 cells;
|
||||
the field buffers total about 1.18 MB. Initial blocks are packed in short main-thread
|
||||
time slices and transferred as `Int32Array` records `(x, y, z, block)`. Subsequent
|
||||
messages carry numeric block deltas, section unloads and changed definitions,
|
||||
instead of repeatedly cloning the full loaded block map.
|
||||
|
||||
`terrain-state.js` computes fields through `block-light.js`, compares old/new
|
||||
light values around section neighborhoods, and builds affected static geometry
|
||||
through `mesh-geometry.js`. Propagation, light comparison, AO sampling, face culling
|
||||
and mesh generation therefore all run in the worker. Vertex samples blend
|
||||
accessible neighbors outside each face and avoid sampling through solid corners.
|
||||
The worker keeps its field arrays and transfers copies for moving actors to
|
||||
sample on the main thread. Epoch/version checks reject obsolete results; dirty
|
||||
section notifications from skipped intermediate fields are retained so a later
|
||||
result cannot leave an old visible mesh with stale lighting.
|
||||
|
||||
Material definitions also invalidate geometry independently of light values.
|
||||
The worker compares transmitted material signatures, finds loaded sections using
|
||||
changed definitions, and refreshes those sections and their AO/culling neighbors.
|
||||
This replaces a retained placeholder when its real opaque material arrives even
|
||||
if the light field is unchanged. Repeated identical definitions do not trigger
|
||||
extra remeshing; pending material changes are combined across coalesced updates.
|
||||
|
||||
The main thread receives transferable opaque/translucent vertex arrays. It
|
||||
uploads them in steps of at most 64 KiB with a 2 ms scheduling budget per frame,
|
||||
retaining the old visible section until both replacements are complete. The
|
||||
section object keeps its identity when its GPU handles are replaced. There is
|
||||
one mesh request in flight and at most two completed results waiting for upload.
|
||||
GPU allocation and individual driver calls cannot be preempted; the scheduling
|
||||
budget does not guarantee that every frame finishes in 2 ms.
|
||||
|
||||
The browser's world map is also indexed by section, allowing validated chunk
|
||||
transitions to update entering/departing blocks without reparsing the entire
|
||||
retained volume. If the terrain worker is unavailable or fails at runtime, the
|
||||
renderer keeps existing visible meshes and falls back to main-thread terrain
|
||||
meshing plus the former `BlockLightController`. That controller can use its own
|
||||
light worker, or calculate light on the main thread when workers are unavailable.
|
||||
Fallback mode can therefore pause rendering during heavy calculations.
|
||||
|
||||
Canonical levels remain scalar. Warm torch light, cool sea-lantern light and
|
||||
other source tints are a Shacraft visual treatment of those levels. They are not
|
||||
a claim that vanilla Java lighting stores RGB light. The shader converts the
|
||||
field to linear irradiance and combines it with the existing sun shadows and
|
||||
ambient occlusion. At block/sky level 0 only a small visibility floor remains;
|
||||
the daytime sky is not reflected or fogged brightly through a sealed room.
|
||||
|
||||
F3 shows block/sky levels at the camera, source count and build status, plus
|
||||
worker/fallback mode, pending geometry, packet-preparation time, worker mesh-build
|
||||
time, geometry-upload time and recent frame-time p95/maximum. Canvas attributes
|
||||
`data-terrain-mode`, `data-terrain-prepare-ms`, `data-mesh-build-ms`, and
|
||||
`data-mesh-upload-ms` distinguish background work from main-thread upload work.
|
||||
The enclosed room in `/tests/renderer-smoke.html` supports source on/off/color changes
|
||||
and removal/restoration of a partition, with explicit canonical readings.
|
||||
|
||||
The game opens at night by default. The lighting button in the game menu switches
|
||||
between day and night and remembers the choice in this browser. Night uses a
|
||||
dark sky, stars, moonlight and matching fog/water reflections. This changes sky
|
||||
illumination in the shader only: propagated block/sky levels, lamp strength and
|
||||
terrain meshes remain unchanged. The setting is local; there is no synchronized
|
||||
server day/night cycle yet. The renderer fixture keeps its daytime default.
|
||||
|
||||
## Boundaries
|
||||
|
||||
Lighting is computed for the client's loaded view, with an exposed sky boundary
|
||||
above that volume and closed unknown side/bottom boundaries. It does not yet
|
||||
receive a full-world authoritative sky heightmap, so a roof above the loaded
|
||||
vertical range can require more world context. Rebuilding a field after an edit
|
||||
has a short worker/update delay. Colored tints and display brightness are visual
|
||||
choices; global illumination and ray-traced point-light shadows are not used.
|
||||
|
||||
The fields are currently renderer state. This change does not add light-dependent
|
||||
mob spawning, crop growth, redstone updates, or other absent gameplay systems.
|
||||
|
||||
## Procedural world columns
|
||||
|
||||
In the v2 world stream, the server supplies full-height opaque column maxima. These seed the top of the local skylight volume and preserve dark caves when the roof is outside the vertical view. Roof edits update the column; unloading a horizontal column releases its data. Sky rendering follows the camera sky exposure so the unloaded underground horizon stays dark. The active light field remains bounded to the streamed window; this is not global propagation over the entire world. See [world streaming](WORLD_STREAMING.md).
|
||||
Reference in New Issue
Block a user