Add light propagation between sub-levels, world#415
Conversation
…o preserve injections from dynamic light mods (e.g. SodiumDynamicLights). Add backward compatibility shims for EntitySubLevelUtil.getEyePositionInterpolated and getTrackingSubLevel to prevent NoSuchMethodError with Simulated/Create Aeronautics.
…s and other sub-levels. Uses a virtual light spread system with manhattan distance falloff on the client side, injected into both vanilla and Sodium light pipelines.
…minate nearby sub-level blocks. Scans for light emitters near each sub-level's visual position on the server, transforms their positions into plot-local coordinates, and injects them into the plot's light engine for proper propagation. Rescans on light changes, sub-level creation/split, and every 8 blocks of movement.
…o preserve injections from dynamic light mods (e.g. SodiumDynamicLights). Add backward compatibility shims for EntitySubLevelUtil.getEyePositionInterpolated and getTrackingSubLevel to prevent NoSuchMethodError with Simulated/Create Aeronautics.
…s and other sub-levels. Uses a virtual light spread system with manhattan distance falloff on the client side, injected into both vanilla and Sodium light pipelines.
…minate nearby sub-level blocks. Scans for light emitters near each sub-level's visual position on the server, transforms their positions into plot-local coordinates, and injects them into the plot's light engine for proper propagation. Rescans on light changes, sub-level creation/split, and every 8 blocks of movement.
Light-emitting blocks on one sub-level now illuminate nearby other sub-levels. Emitters are discovered by scanning other sub-levels' plot chunks, transforming positions to world space, and injecting them into the receiving sub-level's plot light engine. Detection: LevelChunkMixin tracks when a block's light emission changes on a sub-level plot and notifies nearby sub-levels to rescan. Only triggers when emission actually changes (oldState vs newState), avoiding unnecessary work from non-light block updates. Movement: When any sub-level moves, nearby sub-levels are marked for rescan so they pick up emitters at updated world-space positions. Cleanup fix: Old injected positions are cleared unconditionally during reinject, since they are plot-local coordinates that cannot be validated against world state. Performance: Light updates now use ClientboundLightUpdatePacket instead of full chunk resends (ClientboundLevelChunkWithLightPacket), avoiding client-side chunk state resets that caused visual glitches with other mods (e.g. Create ropes) and reducing network overhead.
|
Has this been written with any help from LLM's or gAI tools? |
Initial architecture, starting implementation and bug-fixing\tuning\testing done by me, grunt work of rewriting injects/samplers/etc to spec and code commenting was done using gAI |
|
After discussion with the others, this is not the correct solution for lighting between the normal world and sublevels, also for future reference the CLA mentions the following:
Any code written by a LLM or gAI model is not considered your own, original work. |
|
@IThundxr Sorry for necroposting, but is there a vision for the correct solution among the development team, or is it just a case of "shouldn't be like this"? I mainly did this because lack of lighting is a dealbreaker for me, and i obviously can continue playing with my implementation, but i'd be open to try my hand at another approach if you guys have one, or a concept of it :) Currently I didn't find any hint at this functionality in the codebase, and issue mentioning this is unanswered, so I couldn't figure the intended way out. Thank you for the feedback! |
Overview
Implements bidirectional light propagation across all boundaries: world ↔ sub-level, sub-level ↔ world and sub-level ↔ sub-level. Also fixes compatibility with dynamic lighting mods and adds backward compatibility shims for dependent mods (I believe this was already fixed? Although still with Override usage. This is singled out in a separate commit anyways)
Those features are by no means ready-to-ship and are better viewed as an experimental build. However, after testing i did not find any major visual bugs present.
Light Propagation
World → Sub-level (server-side):
ServerSubLevelLightInjectorscans world blocks near each sub-level's visual bounding box for light emittersTransforms world positions into plot-local coordinates and injects emission values directly into the plot's
BlockLightEngineviasetStoredLevel+enqueueIncreaseRescans on world light changes, sub-level creation/split, and every 8 blocks of movement (so the brightest light still isn't missed, with brightest being 16 i believe and 8 being half of that)
Per-source NPE handling for plot sections without allocated DataLayers
Sub-level → World (client-side):
VirtualLightManagercollects emitting blocks from sub-level plots, transforms to world space, and spreads virtual light with manhattan distance falloffInjected into vanilla via
BlockLightSectionStoragemixin and Sodium viaLevelSlicemixinServer-side implementation would have to work with
ThreadedLevelLightEngineand i don't have a clue how to do thatSub-level → Sub-level (server-side):
fullRescaniterates nearby sub-levels' plot chunks, reads block states for emitters, transforms positions to world space viaPose3d.transformPosition, and injects into the receiving sub-level's plot light engineLevelChunkMixindetects when a block's light emission changes on a sub-level plot (comparing old vs new state) and marks nearby sub-levels for rescanMoving sub-levels mark nearby sub-levels dirty so they pick up emitters at updated positions
Old injected positions cleared unconditionally during reinject (plot-local coords can't be validated against world state)
Performance
Light updates sent via
ClientboundLightUpdatePacket, no full chunk resends and avoiding client-side state resetsDynamic Light Compatibility
EntityRendererMixin: Changed @overwrite to @Inject + @reDIrect for
getPackedLightCoordsto preserve other mods' injections intogetBlockLightLevelEntitySubLevelUtil: Added deprecated shims forgetEyePositionInterpolatedandgetTrackingSubLevelto prevent NoSuchMethodError with Simulated/Create AeronauticsAdding dynamic light compatibility to sub-levels is way beyond my possibilities, so no dynlight for that
Performance Impact
spark_profiles.zip
Tested with Spark profiler comparing original mod vs this PR:
The overhead comes from scanning nearby sub-levels' plot chunks for emitters during rescan. This is bounded by the number of nearby sub-levels and their chunk count.
Visual Comparison
Before:

After:

Before:

After:

Video Preview:
https://youtu.be/swGskrNbTl8
Release
Built binaries are available in the forked repo
Note
Commit history is slightly messed, first 3 commits are duplicated