Lighting System
Lighting System
Section titled “Lighting System”The lighting system calculates and propagates light through the world using a flood-fill algorithm with support for colored block light and skylight.
Package Location
Section titled “Package Location”com.hypixel.hytale.server.core.universe.world.lighting
Overview
Section titled “Overview”Hytale uses a 4-channel lighting system:
- Red block light (0-15)
- Green block light (0-15)
- Blue block light (0-15)
- Skylight (0-15)
Light is calculated per chunk section (32x32x32 blocks) using flood-fill propagation.
Light Channels
Section titled “Light Channels”| Channel | Bits | Range | Source |
|---|---|---|---|
| Red | 0-3 | 0-15 | Block light sources |
| Green | 4-7 | 0-15 | Block light sources |
| Blue | 8-11 | 0-15 | Block light sources |
| Skylight | 12-15 | 0-15 | Sky exposure |
Combined format: 16-bit short value
Core Classes
Section titled “Core Classes”ChunkLightingManager
Section titled “ChunkLightingManager”Main manager running on a dedicated daemon thread per world:
package com.hypixel.hytale.server.core.universe.world.lighting;
public class ChunkLightingManager implements Runnable { public ChunkLightingManager(World world);
public World getWorld();
public void setLightCalculation(LightCalculation lightCalculation); public LightCalculation getLightCalculation();
public void addToQueue(Vector3i chunkPosition);
public void init(WorldChunk worldChunk);
public boolean isQueued(int chunkX, int chunkZ); public boolean isQueued(Vector3i chunkPosition); public int getQueueSize();
public boolean invalidateLightAtBlock( WorldChunk worldChunk, int blockX, int blockY, int blockZ, BlockType blockType, int oldHeight, int newHeight );
public boolean invalidateLightInChunk(WorldChunk worldChunk);
public boolean invalidateLightInChunkSection( WorldChunk worldChunk, int sectionIndex );
public boolean invalidateLightInChunkSections( WorldChunk worldChunk, int sectionIndexFrom, int sectionIndexTo );
public void invalidateLoadedChunks();}LightCalculation
Section titled “LightCalculation”Interface for pluggable light calculation algorithms:
package com.hypixel.hytale.server.core.universe.world.lighting;
public interface LightCalculation { void init(WorldChunk worldChunk);
CalculationResult calculateLight(Vector3i chunkPosition);
boolean invalidateLightAtBlock( WorldChunk worldChunk, int blockX, int blockY, int blockZ, BlockType blockType, int oldHeight, int newHeight );
boolean invalidateLightInChunkSections( WorldChunk worldChunk, int sectionIndexFrom, int sectionIndexTo );}CalculationResult
Section titled “CalculationResult”package com.hypixel.hytale.server.core.universe.world.lighting;
public enum CalculationResult { NOT_LOADED, DONE, INVALIDATED, WAITING_FOR_NEIGHBOUR}FloodLightCalculation
Section titled “FloodLightCalculation”Default implementation using flood-fill algorithm:
package com.hypixel.hytale.server.core.universe.world.lighting;
public class FloodLightCalculation implements LightCalculation { public FloodLightCalculation(ChunkLightingManager chunkLightingManager);}The flood calculation runs in two phases:
- Local light — block light sources within the section
- Global light — skylight propagation from section borders
Propagation Rules:
| Propagation Type | Light Reduction |
|---|---|
| Direct neighbor (6 faces) | -1 |
| Edge connection (12 edges) | -2 |
| Corner connection (8 corners) | -3 |
| Through Semitransparent/Cutout | Additional -1 |
| Through Solid | Blocked |
FullBrightLightCalculation
Section titled “FullBrightLightCalculation”Debug wrapper that sets all skylight to maximum:
package com.hypixel.hytale.server.core.universe.world.lighting;
public class FullBrightLightCalculation implements LightCalculation { public FullBrightLightCalculation( ChunkLightingManager chunkLightingManager, LightCalculation delegate );
public void setFullBright(WorldChunk worldChunk, int chunkY);}Light Data Storage
Section titled “Light Data Storage”ChunkLightData
Section titled “ChunkLightData”Immutable light storage for chunk sections, stored as an octree:
package com.hypixel.hytale.server.core.universe.world.chunk.section;
public class ChunkLightData { public static final int TREE_SIZE = 8; public static final byte MAX_VALUE = 15; public static final int CHANNEL_COUNT = 4;
public static final int RED_CHANNEL = 0; public static final int GREEN_CHANNEL = 1; public static final int BLUE_CHANNEL = 2; public static final int SKY_CHANNEL = 3;
public byte getRedBlockLight(int index); public byte getRedBlockLight(int x, int y, int z); public byte getGreenBlockLight(int index); public byte getGreenBlockLight(int x, int y, int z); public byte getBlueBlockLight(int index); public byte getBlueBlockLight(int x, int y, int z); public byte getSkyLight(int index); public byte getSkyLight(int x, int y, int z);
public byte getBlockLightIntensity(int index); public byte getBlockLightIntensity(int x, int y, int z);
public short getBlockLight(int index); public short getBlockLight(int x, int y, int z);
public byte getLight(int index, int channel);
public short getLightRaw(int index); public short getLightRaw(int x, int y, int z);
public static short combineLightValues( byte red, byte green, byte blue, byte sky ); public static short combineLightValues( byte red, byte green, byte blue ); public static byte getLightValue(short value, int channel);}ChunkLightDataBuilder
Section titled “ChunkLightDataBuilder”Mutable builder for light calculation (extends ChunkLightData):
public class ChunkLightDataBuilder extends ChunkLightData { public ChunkLightDataBuilder(short changeId); public ChunkLightDataBuilder(ChunkLightData lightData, short changeId);
public void setBlockLight(int index, byte red, byte green, byte blue); public void setBlockLight(int x, int y, int z, byte red, byte green, byte blue);
public void setLight(int index, int channel, byte value);
public void setSkyLight(int index, byte light); public void setSkyLight(int x, int y, int z, byte light);
public void setLightRaw(int index, short value);
public ChunkLightData build();}Block Light Sources
Section titled “Block Light Sources”Blocks define their light emission in their block type definition:
public class BlockType { public ColorLight getLight(); public Opacity getOpacity();}Opacity
Section titled “Opacity”package com.hypixel.hytale.protocol;
public enum Opacity { Solid, Semitransparent, Cutout, Transparent}ColorLight
Section titled “ColorLight”Light color and radius definition:
package com.hypixel.hytale.protocol;
public class ColorLight { public byte radius; public byte red; public byte green; public byte blue;
public ColorLight(byte radius, byte red, byte green, byte blue);}Usage Examples
Section titled “Usage Examples”Invalidating Light at Block
Section titled “Invalidating Light at Block”import com.hypixel.hytale.server.core.universe.world.lighting.ChunkLightingManager;
World world = Universe.get().getDefaultWorld();ChunkLightingManager chunkLighting = world.getChunkLighting();
WorldChunk chunk = world.getChunkIfInMemory( ChunkUtil.indexChunkFromBlock(blockX, blockZ));
chunkLighting.invalidateLightAtBlock( chunk, blockX, blockY, blockZ, blockType, oldHeight, newHeight);Reading Light Values
Section titled “Reading Light Values”import com.hypixel.hytale.server.core.universe.world.chunk.section.ChunkLightData;
WorldChunk chunk = world.getChunkIfInMemory( ChunkUtil.indexChunkFromBlock(position.x, position.z));int sectionIndex = position.y >> 5;BlockSection section = chunk.getBlockChunk().getSectionAtIndex(sectionIndex);ChunkLightData lightData = section.getGlobalLight();
int localX = position.x & 31;int localY = position.y & 31;int localZ = position.z & 31;int index = ChunkUtil.indexBlock(localX, localY, localZ);
byte red = lightData.getRedBlockLight(index);byte green = lightData.getGreenBlockLight(index);byte blue = lightData.getBlueBlockLight(index);byte sky = lightData.getSkyLight(index);
byte blockLight = lightData.getBlockLightIntensity(index);
short rawLight = lightData.getLightRaw(index);Switching Light Calculation Mode
Section titled “Switching Light Calculation Mode”import com.hypixel.hytale.server.core.universe.world.lighting.*;
ChunkLightingManager chunkLighting = world.getChunkLighting();LightCalculation current = chunkLighting.getLightCalculation();chunkLighting.setLightCalculation( new FullBrightLightCalculation(chunkLighting, current));
chunkLighting.invalidateLoadedChunks();Light Propagation Algorithm
Section titled “Light Propagation Algorithm”Local Light (Block Light)
Section titled “Local Light (Block Light)”- Find all light-emitting blocks in section
- Add their positions to propagation queue
- For each position in queue:
- Check 6 direct neighbors
- If neighbor has lower light, update and queue
- Apply opacity reduction
- Continue until queue is empty
Global Light (Skylight)
Section titled “Global Light (Skylight)”- Start from section borders
- Three propagation phases:
- Sides: Direct neighbors (-1 reduction)
- Edges: Edge connections (-2 reduction)
- Corners: Corner connections (-3 reduction)
- Check neighbor chunk sections if needed
- Wait for neighbors if not yet calculated

Commands
Section titled “Commands”Built-in lighting commands:
| Command | Description |
|---|---|
/lighting calculation flood | Switch to flood algorithm |
/lighting calculation fullbright | Enable full brightness |
/lighting invalidate | Recalculate all loaded chunks |
/lighting invalidate --one | Recalculate player’s chunk section |
/lighting info | Show lighting queue size and calculation type |
/lighting info --detail | Show per-section local/global light counts |
Performance Considerations
Section titled “Performance Considerations”- Async Processing: Light calculation runs on dedicated thread
- Queue-based: Changes are queued and processed in order
- Section Granularity: Updates are per 32x32x32 section
- Neighbor Dependencies: Sections wait for neighbors before completing
- Octree Storage: Compact representation reduces memory
Related
Section titled “Related”- Dynamic Lighting - Entity light sources
- World System - Chunk management
- Block System - Block light properties