Skip to content

Dynamic Lighting

Dynamic lighting allows entities to emit light that moves with them. The system supports both temporary runtime lights and persistent lights that survive entity respawn.

  • Components: com.hypixel.hytale.server.core.modules.entity.component
  • Systems: com.hypixel.hytale.server.core.modules.entity.dynamiclight

Dynamic lights are ECS components attached to entities. Two component types exist:

ComponentPersistenceUse Case
DynamicLightRuntime onlyTemporary effects (spell glow, fire)
PersistentDynamicLightSaved with entityPermanent lights (lantern entity)

Runtime light component for entities:

package com.hypixel.hytale.server.core.modules.entity.component;
public class DynamicLight implements Component<EntityStore> {
public DynamicLight();
public DynamicLight(ColorLight colorLight);
public ColorLight getColorLight();
public void setColorLight(ColorLight colorLight);
public boolean consumeNetworkOutdated();
public static ComponentType<EntityStore, DynamicLight> getComponentType();
}

Serializable light component that persists with entity data:

package com.hypixel.hytale.server.core.modules.entity.component;
public class PersistentDynamicLight implements Component<EntityStore> {
public static final BuilderCodec<PersistentDynamicLight> CODEC;
public PersistentDynamicLight(ColorLight colorLight);
public ColorLight getColorLight();
public void setColorLight(ColorLight colorLight);
public static ComponentType<EntityStore, PersistentDynamicLight> getComponentType();
}

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();
public ColorLight(byte radius, byte red, byte green, byte blue);
public ColorLight(ColorLight other);
public ColorLight clone();
}

Contains systems for managing dynamic lights:

package com.hypixel.hytale.server.core.modules.entity.dynamiclight;
public class DynamicLightSystems {
// creates DynamicLight from PersistentDynamicLight when entity is added
public static class Setup extends HolderSystem<EntityStore> {
// query: has PersistentDynamicLight AND NOT DynamicLight
// onEntityAdd: creates DynamicLight from persistent light
}
// notifies clients when a DynamicLight component is removed
public static class EntityTrackerRemove
extends RefChangeSystem<EntityStore, DynamicLight> {
// onComponentRemoved: sends ComponentUpdateType.DynamicLight to trackers
}
}
import com.hypixel.hytale.server.core.modules.entity.component.DynamicLight;
import com.hypixel.hytale.protocol.ColorLight;
// create light (radius 8, warm orange glow)
ColorLight torchLight = new ColorLight((byte) 8, (byte) 15, (byte) 10, (byte) 5);
// add dynamic light component to entity
DynamicLight light = new DynamicLight(torchLight);
store.addComponent(entityRef, DynamicLight.getComponentType(), light);
import com.hypixel.hytale.server.core.modules.entity.component.PersistentDynamicLight;
import com.hypixel.hytale.protocol.ColorLight;
// create persistent light (survives respawn/reload)
ColorLight lanternLight = new ColorLight((byte) 12, (byte) 15, (byte) 15, (byte) 12);
PersistentDynamicLight persistentLight = new PersistentDynamicLight(lanternLight);
// add to entity — DynamicLight will be auto-created by the Setup system
store.addComponent(entityRef, PersistentDynamicLight.getComponentType(), persistentLight);
import com.hypixel.hytale.server.core.modules.entity.component.DynamicLight;
import com.hypixel.hytale.protocol.ColorLight;
// get existing light component
DynamicLight light = store.getComponent(entityRef, DynamicLight.getComponentType());
// update to new color (flickering effect)
ColorLight flickerLight = new ColorLight(
light.getColorLight().radius,
(byte) random.nextInt(12, 16),
(byte) random.nextInt(8, 12),
(byte) random.nextInt(3, 7)
);
light.setColorLight(flickerLight);
import com.hypixel.hytale.server.core.modules.entity.component.DynamicLight;
// remove light component — EntityTrackerRemove system will notify clients
store.removeComponent(entityRef, DynamicLight.getComponentType());
import com.hypixel.hytale.server.core.modules.entity.component.DynamicLight;
import com.hypixel.hytale.component.query.Query;
// query for entities with dynamic lights
Query<EntityStore> lightQuery = Query.builder(EntityStore.class)
.with(DynamicLight.getComponentType())
.build();
for (ArchetypeChunk<EntityStore> chunk : store.query(lightQuery)) {
DynamicLight[] lights = chunk.getComponentArray(DynamicLight.getComponentType());
for (int i = 0; i < chunk.getEntityCount(); i++) {
ColorLight color = lights[i].getColorLight();
}
}

ColorLight has no built-in presets. You define your own values using the byte fields directly.

Here are some illustrative examples to get you started:

ExampleRadiusRGBDescription
Warm torch815105Orange glow
Bright lantern12151512Warm white
Red glow71500Pure red
Cool blue1051215Blue-cyan
// illustrative — define your own presets
ColorLight warmTorch = new ColorLight((byte) 8, (byte) 15, (byte) 10, (byte) 5);
ColorLight brightLantern = new ColorLight((byte) 12, (byte) 15, (byte) 15, (byte) 12);

Dynamic lights are automatically synchronized to clients:

  1. On Add: Light component sent with entity spawn
  2. On Update: setColorLight() marks network dirty
  3. On Remove: EntityTrackerRemove system notifies trackers
  4. Update Type: ComponentUpdateType.DynamicLight

Dynamic entity lights work alongside chunk-based lighting:

  • Chunk Light: Static, calculated once, stored in ChunkLightData
  • Dynamic Light: Real-time, follows entity, rendered client-side

The client combines both light sources for final illumination.

PersistentDynamicLight is saved with entity data:

{
"Components": {
"Light": {
"Radius": 8,
"Red": 15,
"Green": 10,
"Blue": 5
}
}
}

The codec is defined on PersistentDynamicLight.CODEC and uses ProtocolCodecs.COLOR_LIGHT via BuilderCodec with the key "Light".

  1. Use Persistent for permanent lights: Lanterns, glowing items, etc.
  2. Use Runtime for effects: Spell glows, fire, temporary buffs
  3. Limit light count: Many dynamic lights can impact performance
  4. Reasonable radius: Keep radius under 15 for best results
  5. Update frequency: Don’t update every tick unless needed (flickering)