Skip to content

API reference / @jsprismarine/lighting / LightEngine

Class: LightEngine ​

Defined in: LightEngine.ts:78

The server's internal light model: a block light layer that floods out of emitters and a sky light layer that falls from the open sky, both kept current as blocks change and both advanced in bounded steps so a tick cannot stall.

These levels never reach a player. The Bedrock protocol has no light packet and neither LevelChunkPacket nor SubChunkPacket carries light arrays, so the connected client computes and renders light itself from the block palette it already has. The server keeps its own copy for the three rules that read it: mob spawning, crop growth, and daylight detectors. Where the two models disagree, the player sees the client's answer and the server acts on this one.

Java's directional opacity, which lets a slab, a stair or a piston pass light in some directions and not others, is deliberately not implemented. Bedrock's block data expresses one minecraft:light_dampening scalar per state with no direction, the Bedrock client applies that scalar, and a server that modeled Java's per-face rule would compute light the client contradicts for every slab and stair in the world.

The engine reads the world through an injected BlockLightView and holds no reference to chunk, block or world classes. The server has to announce a chunk with LightEngine.onChunkLoaded before the engine stores light in it.

Constructors ​

Constructor ​

new LightEngine(view): LightEngine

Defined in: LightEngine.ts:84

Parameters ​

view ​

BlockLightView

Returns ​

LightEngine

Accessors ​

pending ​

Get Signature ​

get pending(): LightQueueDepth

Defined in: LightEngine.ts:92

The work the engine still has to do. LightEngine.flush returns the same numbers.

Returns ​

LightQueueDepth

Methods ​

flush() ​

flush(budget?): LightFlushResult

Defined in: LightEngine.ts:228

Advances the light by at most budget queue nodes and reports what is left, so a tick can spend a fixed amount of time on light and decide from the result whether to come back.

Every decrease node runs before any increase node, which is what makes a removed light source darken its neighborhood before the surviving sources fill it in again. Stopping mid-flush leaves the light part way through that sequence: levels are readable but not yet correct, and they become correct once queued reaches 0.

Parameters ​

budget? ​

number = Number.POSITIVE_INFINITY

The most nodes to process. Unbounded when omitted.

Returns ​

LightFlushResult

The work done and the work left.

Throws ​

When the budget is negative or not a number.


getBlockLight() ​

getBlockLight(x, y, z): number

Defined in: LightEngine.ts:104

The block light at a world position, 0 to 15.

Parameters ​

x ​

number

World x.

y ​

number

World y.

z ​

number

World z.

Returns ​

number

The level, or 0 for a position in a column the engine has not been told about. Check that the chunk is loaded before reading a 0 as darkness.


getSkyLight() ​

getSkyLight(x, y, z): number

Defined in: LightEngine.ts:119

The sky light at a world position, 0 to 15, before the time of day and the weather scale it. The daylight cycle multiplies this number; it does not change it.

Parameters ​

x ​

number

World x.

y ​

number

World y.

z ​

number

World z.

Returns ​

number

The level, 0 in a dimension with no sky and 0 for a position in a column the engine has not been told about.


hasChunk() ​

hasChunk(chunkX, chunkZ): boolean

Defined in: LightEngine.ts:87

Whether this engine currently holds lighting for a chunk column.

Parameters ​

chunkX ​

number

chunkZ ​

number

Returns ​

boolean


onBlockChanged() ​

onBlockChanged(position, oldState, newState): void

Defined in: LightEngine.ts:198

Queues the smallest piece of work that makes both layers correct again after one block changed. Nothing is computed here; LightEngine.flush does the computing.

The sky layer is patched rather than rebuilt: the column's heightmap entry moves only when the change was at or above the highest light-blocking block, and the only scan is the walk down the column that finds the next blocker after the top one is broken.

A change that alters neither emission nor dampening queues nothing, so a server can call this for every block change without filtering first.

Parameters ​

position ​

BlockPosition

Where the block changed.

oldState ​

BlockLightProperties

The light properties of the block that was there.

newState ​

BlockLightProperties

The light properties of the block that is there now.

Returns ​

void


onChunkLoaded() ​

onChunkLoaded(chunkX, chunkZ): void

Defined in: LightEngine.ts:136

Takes a chunk into the light model and computes its light from scratch: it builds the sky heightmap, makes every emitter in the column a source, and re-seeds across the border of each loaded neighbor so light that stopped at the chunk's edge while it was absent flows in.

Calling this for a chunk the engine already holds discards that chunk's stored light and computes it again, which is how a caller forces a full recompute.

Parameters ​

chunkX ​

number

The chunk x.

chunkZ ​

number

The chunk z.

Returns ​

void


onChunkUnloaded() ​

onChunkUnloaded(chunkX, chunkZ): void

Defined in: LightEngine.ts:180

Drops a chunk's stored light. Light in the neighbors that came from this chunk is left as it is; it is recomputed when the chunk comes back, because LightEngine.onChunkLoaded re-seeds across the border.

Parameters ​

chunkX ​

number

The chunk x.

chunkZ ​

number

The chunk z.

Returns ​

void