Lighting System
Scope note: This page only describes behavior that is visible in the decompiled server code.
The lighting system lives under com.hypixel.hytale.server.core.universe.world.lighting.
High-level architecture
Section titled “High-level architecture”ChunkLightingManager
Section titled “ChunkLightingManager”com.hypixel.hytale.server.core.universe.world.lighting.ChunkLightingManager:
- Belongs to a
Worldand is accessible viaworld.getChunkLighting(). - Spawns a daemon thread named
"ChunkLighting - " + world.getName(). - Maintains a queue of
Vector3ipositions (chunkX, chunkY, chunkZ) to (re)light. - Delegates calculation to a pluggable
LightCalculationimplementation.- By default it uses
FloodLightCalculation.
- By default it uses
The manager’s run() loop dequeues work and calls calculateLight(...). If the queue stays stable for long enough, it blocks on a Semaphore until new work is enqueued.
CalculationResult
Section titled “CalculationResult”Lighting calculations return CalculationResult:
NOT_LOADEDDONEINVALIDATEDWAITING_FOR_NEIGHBOUR
If a calculation returns INVALIDATED, the same chunk position is re-enqueued.
Where light data is stored
Section titled “Where light data is stored”Lighting is stored per block section in BlockSection:
BlockSection.localLight/BlockSection.globalLightareChunkLightData.BlockSection.localChangeCounter/globalChangeCounterare incremented when invalidated.BlockSection.hasLocalLight()islocalLight.changeId == localChangeCounter.BlockSection.hasGlobalLight()isglobalLight.changeId == globalChangeCounter.
ChunkLightData format
Section titled “ChunkLightData format”com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkLightData stores 4 channels (4 bits each):
- red (0)
- green (1)
- blue (2)
- sky (3)
It provides helpers like getSkyLight(index) and getBlockLightIntensity(index).
Internally the data is stored as an octree-like structure inside a Netty ByteBuf (see getTraverse(...) and serializeOctree(...)).
FloodLightCalculation (default algorithm)
Section titled “FloodLightCalculation (default algorithm)”com.hypixel.hytale.server.core.universe.world.lighting.FloodLightCalculation implements LightCalculation and performs two phases per section:
- Local light: computed from within the section’s own blocks/fluids.
- Global light: computed by propagating from neighbouring sections’ local light onto this section.
Local light seeding includes blocks and fluids
Section titled “Local light seeding includes blocks and fluids”When building local light for a section, floodChunkSection(...):
- Sets sky light to
15for blocks at or above the height map (originY >= height), otherwise0. - Seeds RGB light from:
BlockType.getLight()for the block at that position, and/orFluid.getLight()for the fluid at that position.
If both exist, it combines by taking the per-channel max and keeps the computed sky light.
Propagation rules (opacity)
Section titled “Propagation rules (opacity)”The propagation step (propagateLight(...)) walks a BitSet queue of lit blocks:
- If the current block’s
BlockType.getOpacity()isOpacity.Solid, it does not propagate from that block. - Otherwise each step reduces each channel by at least
1. - If the opacity is
Opacity.SemitransparentorOpacity.Cutout, it reduces each channel by an extra1.
This propagation is applied for RGB and sky channels.
Global light depends on neighbours having local light
Section titled “Global light depends on neighbours having local light”Before computing global light, the algorithm checks neighbouring sections for local light availability (testNeighboursForLocalLight(...)). If any neighbour is missing local light, it returns WAITING_FOR_NEIGHBOUR.
Global light is seeded from neighbour section faces/edges/corners (using Vector3i.BLOCK_SIDES, BLOCK_EDGES, BLOCK_CORNERS) and then propagated through the section.
Invalidation (when you change the world)
Section titled “Invalidation (when you change the world)”Invalidate from blocks
Section titled “Invalidate from blocks”The lighting manager exposes:
invalidateLightAtBlock(WorldChunk, blockX, blockY, blockZ, BlockType, oldHeight, newHeight)invalidateLightInChunkSection(WorldChunk, sectionIndex)invalidateLightInChunkSections(WorldChunk, from, to)
FloodLightCalculation.invalidateLightInChunkSections(...) invalidates a 3×3 chunk area around the target chunk:
- For the target chunk, it invalidates local light on affected sections.
- For neighbour chunks, it invalidates global light on affected sections.
- It then enqueues all affected
(chunkX, chunkY, chunkZ)positions into the lighting queue.
Invalidate from fluids
Section titled “Invalidate from fluids”The builtin fluid replication system schedules lighting invalidation when fluids change:
world.getChunkLighting().invalidateLightInChunkSection(worldChunk, sectionY)
(See com.hypixel.hytale.builtin.fluid.FluidSystems.ReplicateChanges.)
Practical mod patterns (code-backed)
Section titled “Practical mod patterns (code-backed)”Query light levels
Section titled “Query light levels”If you have a BlockSection for a section, you can read:
- local:
blockSection.getLocalLight().getSkyLight(index)/getBlockLightIntensity(index) - global:
blockSection.getGlobalLight().getSkyLight(index)/getBlockLightIntensity(index)
Force a relight
Section titled “Force a relight”After making bulk changes, you can invalidate at chunk/section granularity via world.getChunkLighting().
Related classes
Section titled “Related classes”com.hypixel.hytale.server.core.universe.world.lighting.ChunkLightingManagercom.hypixel.hytale.server.core.universe.world.lighting.FloodLightCalculationcom.hypixel.hytale.server.core.universe.world.lighting.LightCalculationcom.hypixel.hytale.server.core.universe.world.chunk.section.ChunkLightDatacom.hypixel.hytale.server.core.universe.world.chunk.section.BlockSectioncom.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType(opacity/light)com.hypixel.hytale.server.core.asset.type.fluid.Fluid(light)