Lilium Dynamic Light

Lilium Dynamic Light is a vanilla-friendly addon that brings real-time dynamic lighting to players, mobs, and items.
Back to Files

Lilium Dynamic Light V2.2.0.mcaddon

File nameLilium Dynamic Light V2.2.0.mcaddon
Uploader
LiliumStudioLiliumStudio
Uploaded
Oct 15, 2026
Downloads
847
Size
769.9 KB
File ID
9196239
Type
R
Release
Supported game versions
  • 26.50

What's new

Changelog - Lilium Dynamic Light

[2.2.0]

Changed

  • Script API Updated to @minecraft/server 2.10.0 and @minecraft/server-ui 2.2.0 (Requires Minecraft 1.26.50): Both manifests now depend on the latest stable script modules, and min_engine_version is 1.26.50 for both packs, the first game version in which 2.10.0 is stable. Older clients can no longer load the behavior pack. Every script was type-checked against the 2.10.0 and 2.2.0 typings with no new errors.
  • Configuration Menu Restricted to Operators (Breaking For Multiplayer): The settings live in a world dynamic property and apply to every player, yet the triple-sneak gesture opened the full menu for anyone, so any player on a Realm or server could reset the configuration, turn features off or raise scan distances until the world lagged. canManageConfig() in ui/menu.js now requires PlayerPermissionLevel.Operator or at least CommandPermissionLevel.GameDirectors, and is checked at every menu entry point. A player without permission who sneaks three times gets nothing, since that happens in normal play; one who reaches the menu any other way, for example through an operator's /execute as @a run scriptevent ldl:menu, is told why it did not open (ldl.msg.noPermission, in all 19 languages).
  • Lights Move Without a Trail: An owner now releases its previous light position in the same tick it lights the new one, instead of leaving it lit until the stale-owner sweep expired it interval × 2 + 2 ticks later (6 ticks by default, 42 at interval 20). A source that stops emitting, such as a player switching away from a torch or an item sinking into water, goes dark on that same pulse. The stale-owner sweep is still there for sources that simply stop updating, such as a mob that walks out of detection range.
  • Lava and Fire No Longer Scanned as Emitting Blocks: minecraft:lava, flowing_lava, fire and soul_fire resolved through the item light table, so every lava block in range became its own emitter. Over a Nether lava ocean that meant one light block per surface block, each ticking, plus a marked entry for every submerged block re-evaluated on every sweep. They already emit vanilla light, so they are now excluded from block scanning (BLOCK_SCAN_EXCLUDED_IDS). A user who wants the tint back can still add them in the Blocks menu, which takes precedence over the exclusion.
  • Entity Detection Distance Capped at 64 (Breaking For Existing Worlds Above 64): The maximum was 128 blocks, which queried and resolved every entity in a 128-block radius around every player every two ticks: the same trap the block scan radius had before 2.0.0. MAX_ENTITY_SCAN_DISTANCE is now 64 for both the config clamp and the slider, so saved values above it are clamped on load.
  • Menu Changes Apply to Block Lights Immediately: Only the Ignore List released tracked block lights when it changed. Item, block, color and feature changes left placed block lights on their old level or color until the 100-tick sweep reached them. Every menu change now drops both entity and block lights, and they are rebuilt on the next pulse.

Fixed

  • Extinguished Campfires and Unlit Redstone Lamps Emitting Light (Major Fix): The requiresLit check read a lit block state that Bedrock only defines for candles. Campfires use extinguished, and the unlit and lit redstone lamp are two different identifiers, so getState("lit") returned undefined and every campfire and every unlit minecraft:redstone_lamp was treated as lit, at level 15. Campfires now check extinguished === true, and minecraft:redstone_lamp is gone from the vanilla table (minecraft:lit_redstone_lamp still emits). The flag on minecraft:redstone_torch was dropped too, since its unlit form is also a separate identifier.
  • Offhand Swap Destroying Item Data and Allowing Free Repairs (Major Fix): Moving an item to the offhand ran replaceitem … <id> <amount>, which rebuilt the stack from scratch: names, lore and enchantments were lost and durability reset to full. Since any item can be marked offhand-capable in the Items menu, this doubled as a free repair for elytra and tools. The main hand was also cleared before the command ran, so a failed command deleted the item. The swap now uses setEquipment(), which keeps all item data and reports whether it succeeded in 2.10.0. The main hand is only rewritten once the offhand has accepted the item. replaceitem remains as a fallback only for plain stackable items that still stack with a fresh copy of themselves, which have no data to lose; anything else is left untouched.
  • water Parameter Ignored For Blocks: The water flag of the ldl:light component, the ldl:water block tag, the Blocks menu toggle and the vanilla table were never read for blocks. The light placement decided "underwater" from the source's own cell, which for a block emitter is the block itself, so a submerged emitter never got a light no matter what it declared. Block emitters now pass acceptWater to the engine, and a water-safe emitter lights the water around it, which is restored when the light goes out. The ldl:water tag is also honored on blocks now.
  • Enchanted Armor Making Its Wearer Glow: The vanilla-table and enchanted-item paths of getItemLightLevel() ignored the equipment slot, so any player or mob in enchanted armor glowed at level 5 permanently. Both paths now follow the same rule as custom items without an equip restriction: they glow in either hand and on the ground, not when worn.
  • Burning Entities Emitting White Light: When fire was the brightest source on an entity, no type id was passed on to the color resolver and the light fell back to white. It now resolves as minecraft:fire and is orange under Vibrant Visuals.
  • /scriptevent ldl:fix Draining Water: The cleanup filled every light block in range with air, including lights that had replaced water. It now finds them with Dimension.getBlocks() and restores each one to its ldl:base. The vertical range is clamped to the dimension's height range. The fill fallback is kept for vanilla light_block_* placements from older versions.
  • Settings Silently Lost When the Configuration Grew Too Large: A configuration over the dynamic property size limit failed to save with only a console warning. The menu kept showing the change, and it vanished on the next world load. A failed save now discards the in-memory change and reloads what the world actually stored, and the player sees ldl.msg.saveFailed, in all 19 languages.
  • Emitting Blocks Keeping Stale Light Positions: A block emitter whose light cell was later occupied moved its light elsewhere, but kept the old position registered forever, since static owners are never swept. A light another source later placed there could then stay lit indefinitely. Covered by the trail-free release above, which applies to static and dynamic owners alike.

Optimized

  • Light Block Safety Tick Every 10 Ticks: Every light block ran a script callback on every game tick (interval_range [1, 1]). The engine already restores the blocks it releases itself; the tick only clears lights the engine lost track of, such as those left by a /reload. It now runs every 10 ticks, a tenth of the callbacks, and such orphans clear within about one second instead of two ticks.
  • Vanilla Blocks Resolved Without Native Lookups: The block scan called getComponent("ldl:light") and getTags() twice for every solid block in range, up to 5,625 blocks per player per pulse. Vanilla blocks can carry neither the component nor ldl:* tags, so for minecraft: identifiers resolution now goes straight to the static tables. Add-on blocks read their component and tags in a single getTags() call, and the now-unused LightAPI.resolveBlockLight() and resolveBlockColor() were removed.
  • Pending-Restore Queue Bounded and Exception-Free: Restores that could not land because their chunk was unloaded were retried every 40 ticks with no limit or expiry, each attempt throwing inside getBlock(). Dimension.isChunkLoaded() now short-circuits the attempt, and the queue holds at most 4,096 entries. Dropping the oldest one is safe because the light block's own tick reverts it once its chunk loads.
  • Creeper Event Subscription Filtered at the Source: dataDrivenEntityTrigger was subscribed without options, so every data-driven event of every entity in the world crossed into script only to be discarded. It is now filtered by entityTypes and eventTypes.

This mod has no additional files