Skip to content

Commit

Permalink
LambDynamicLights v3.1.0
Browse files Browse the repository at this point in the history
- Optimize dynamic light lookup thanks to @Akarys42.
- Added support for falling block entities #93.
- Added settings access in Sodium.
  • Loading branch information
LambdAurora committed Oct 22, 2024
1 parent 3c45415 commit 7f0c1f5
Show file tree
Hide file tree
Showing 23 changed files with 413 additions and 138 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@

- Fixed crash due to Mixin plugin ([#239](https://github.com/LambdAurora/LambDynamicLights/issues/239)).

## 3.1.0

- Improved general performances, especially in worst-case scenarios.
- Added support for falling block entities ([#93](https://github.com/LambdAurora/LambDynamicLights/issues/93)).
- Added settings access in Sodium.
- Updated Simplified Chinese translations ([#242](https://github.com/LambdAurora/LambDynamicLights/pull/242)).

[SpruceUI]: https://github.com/LambdAurora/SpruceUI "SpruceUI page"
[pridelib]: https://github.com/Queerbric/pridelib "Pridelib page"
[Sodium]: https://modrinth.com/mod/sodium "Sodium Modrinth page"
Expand Down
18 changes: 8 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- modrinth_exclude.start -->
![Java 21](https://img.shields.io/badge/language-Java%2021-9115ff.svg?style=flat-square) <!-- modrinth_exclude.end -->
[![GitHub license](https://img.shields.io/badge/license-Lambda%20License-c7136d?style=flat-square)](https://raw.githubusercontent.com/LambdAurora/LambDynamicLights/1.19/LICENSE)
[![GitHub license](https://img.shields.io/badge/license-Lambda%20License-c7136d?style=flat-square)](https://raw.githubusercontent.com/LambdAurora/LambDynamicLights/1.21/LICENSE)
![Environment: Client](https://img.shields.io/badge/environment-client-1976d2?style=flat-square)
[![Mod loader: Fabric]][fabric] <!-- modrinth_exclude.start -->
![Version](https://img.shields.io/github/v/tag/LambdAurora/LambDynamicLights?label=version&style=flat-square)
Expand Down Expand Up @@ -47,31 +47,31 @@ Searching other mods to replace OptiFine? [Check out this list!](https://optifin

Dropped items which already emit light as a block, will also dynamically emit light!

![Torch](https://media.forgecdn.net/attachments/301/21/2020-07-04_22.png)
![Torch](images/torch.png)

### Held items emit light

Light is emitted when entities hold light emitting items.

![Fox holding lantern](https://media.forgecdn.net/attachments/301/22/2020-07-04_22.png)
![Fox holding lantern](images/fox_holding_lantern.png)

### Fire! Fire! Fire!

Any entity on fire will emit light!

![Skeleton on fire!](https://media.forgecdn.net/attachments/301/23/2020-07-04_22.png)
![Skeleton on fire!](images/fire_skeleton.png)

### Spectral arrows

Spectral arrows will emit a very weak light!

![Spectral arrows](https://media.forgecdn.net/attachments/301/25/2020-07-04_22.png)
![Spectral arrows](images/spectral_arrow.png)

### Different luminance!

Light emitted from items depend on the light emitted from their respective blocks!

![light levels](https://media.forgecdn.net/attachments/301/26/2020-07-04_22.png)
![light levels](images/light_levels.png)

### Configuration GUI

Expand Down Expand Up @@ -99,11 +99,11 @@ Just do `./gradlew build` and everything should build just fine!

## 📖 How does it work internally?

Check [this documentation](https://github.com/LambdAurora/LambDynamicLights/blob/1.17/HOW_DOES_IT_WORK.md).
Check [this documentation](https://github.com/LambdAurora/LambDynamicLights/blob/1.21/HOW_DOES_IT_WORK.md).

## 📖 Is there an API? How to use it as a developer?

Check [this documentation](https://github.com/LambdAurora/LambDynamicLights/blob/1.17/API.md).
Check [this documentation](https://github.com/LambdAurora/LambDynamicLights/blob/1.21/API.md).

<!-- modrinth_exclude.long_start -->
## Downloads
Expand Down Expand Up @@ -132,13 +132,11 @@ GitHub
# 📖 Compatibility

- [Sodium] is recommended for better performances.
- [Canvas] is compatible but still WIP: expect huge lag spike with it until a proper lighting API is done in Canvas.
- **OptiFabric is obviously incompatible.**

[fabric]: https://fabricmc.net
[Mod loader: Fabric]: https://img.shields.io/badge/modloader-Fabric-1976d2?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAFHGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE4LTEyLTE2VDE2OjU0OjE3LTA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0wNy0yOFQyMToxNzo0OC0wNzowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0wNy0yOFQyMToxNzo0OC0wNzowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowZWRiMWMyYy1mZjhjLWU0NDEtOTMxZi00OTVkNGYxNGM3NjAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MGVkYjFjMmMtZmY4Yy1lNDQxLTkzMWYtNDk1ZDRmMTRjNzYwIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MGVkYjFjMmMtZmY4Yy1lNDQxLTkzMWYtNDk1ZDRmMTRjNzYwIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDowZWRiMWMyYy1mZjhjLWU0NDEtOTMxZi00OTVkNGYxNGM3NjAiIHN0RXZ0OndoZW49IjIwMTgtMTItMTZUMTY6NTQ6MTctMDg6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChXaW5kb3dzKSIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4/HiGMAAAAtUlEQVRYw+XXrQqAMBQF4D2P2eBL+QIG8RnEJFaNBjEum+0+zMQLtwwv+wV3ZzhhMDgfJ0wUSinxZUQWgKos1JP/AbD4OneIDyQPwCFniA+EJ4CaXm4TxAXCC0BNHgLhAdAnx9hC8PwGSRtAFVMQjF7cNTWED8B1cgwW20yfJgAvrssAsZ1cB3g/xckAxr6FmCDU5N6f488BrpCQ4rQBJkiMYh4ACmLzwOQF0CExinkCsvw7vgGikl+OotaKRwAAAABJRU5ErkJggg==
[Fabric API]: https://www.curseforge.com/minecraft/mc-mods/fabric-api "Fabric API CurseForge page"
[ModMenu]: https://modrinth.com/mod/modmenu
[Sodium]: https://www.curseforge.com/minecraft/mc-mods/sodium "Sodium CurseForge page"
[Canvas]: https://www.curseforge.com/minecraft/mc-mods/canvas-renderer "Canvas CurseForge page"
[LambdAurora Discord]: https://discord.lambdaurora.dev
2 changes: 1 addition & 1 deletion build_logic/src/main/kotlin/lambdynamiclights/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.gradle.accessors.dm.LibrariesForLibs
object Constants {
const val GROUP = "dev.lambdaurora"
const val NAME = "lambdynamiclights"
const val VERSION = "3.0.1"
const val VERSION = "3.1.0"
const val JAVA_VERSION = 21

private var minecraftVersion: String? = null
Expand Down
Binary file added images/fire_skeleton.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/fox_holding_lantern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/light_levels.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/spectral_arrow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/torch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
102 changes: 30 additions & 72 deletions src/main/java/dev/lambdaurora/lambdynlights/LambDynLights.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
import dev.lambdaurora.lambdynlights.accessor.WorldRendererAccessor;
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
import dev.lambdaurora.lambdynlights.api.DynamicLightsInitializer;
import dev.lambdaurora.lambdynlights.engine.DynamicLightingEngine;
import dev.lambdaurora.lambdynlights.resource.item.ItemLightSources;
import dev.yumi.commons.event.EventManager;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.fabricmc.loader.api.FabricLoader;
Expand All @@ -28,19 +31,21 @@
import net.minecraft.resources.Identifier;
import net.minecraft.resources.io.ResourceManager;
import net.minecraft.resources.io.ResourceType;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.PrimedTnt;
import net.minecraft.world.entity.monster.Creeper;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockAndTintGetter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Predicate;
Expand All @@ -49,18 +54,18 @@
* Represents the LambDynamicLights mod.
*
* @author LambdAurora
* @version 3.0.1
* @version 3.1.0
* @since 1.0.0
*/
public class LambDynLights implements ClientModInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger("LambDynamicLights");
private static final double MAX_RADIUS = 7.75;
private static final double MAX_RADIUS_SQUARED = MAX_RADIUS * MAX_RADIUS;
public static final EventManager<Identifier> EVENT_MANAGER = new EventManager<>(Identifier.of(LambDynLightsConstants.NAMESPACE, "default"), Identifier::parse);
private static LambDynLights INSTANCE;
public final DynamicLightsConfig config = new DynamicLightsConfig(this);
public final ItemLightSources itemLightSources = new ItemLightSources();
private final DynamicLightingEngine engine = new DynamicLightingEngine();
private final Set<DynamicLightSource> dynamicLightSources = new HashSet<>();
private final List<DynamicLightSource> toClear = new ArrayList<>();
private final ReentrantReadWriteLock lightSourcesLock = new ReentrantReadWriteLock();
private long lastUpdate = System.currentTimeMillis();
private int lastUpdateCount = 0;
Expand Down Expand Up @@ -89,6 +94,18 @@ public void reload(ResourceManager manager) {
}
});

CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> {
this.itemLightSources.apply(registries);
});

ClientTickEvents.END_WORLD_TICK.register(level -> {
this.lightSourcesLock.writeLock().lock();
this.engine.computeSpatialLookup(this.dynamicLightSources);
this.toClear.forEach(source -> source.lambdynlights$scheduleTrackedChunksRebuild(Minecraft.getInstance().levelRenderer));
this.toClear.clear();
this.lightSourcesLock.writeLock().unlock();
});

WorldRenderEvents.START.register(context -> {
Minecraft.getInstance().getProfiler().swap("dynamic_lighting");
this.updateAll(context.worldRenderer());
Expand All @@ -111,11 +128,9 @@ public void updateAll(@NotNull LevelRenderer renderer) {
this.lastUpdate = now;
this.lastUpdateCount = 0;

this.lightSourcesLock.readLock().lock();
for (var lightSource : this.dynamicLightSources) {
if (lightSource.lambdynlights$updateDynamicLight(renderer)) this.lastUpdateCount++;
}
this.lightSourcesLock.readLock().unlock();
}
}

Expand All @@ -131,11 +146,12 @@ public int getLastUpdateCount() {
/**
* Returns the lightmap with combined light levels.
*
* @param level the level in which the light is computed
* @param pos the position
* @param lightmap the vanilla lightmap coordinates
* @return the modified lightmap coordinates
*/
public int getLightmapWithDynamicLight(@NotNull BlockPos pos, int lightmap) {
public int getLightmapWithDynamicLight(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, int lightmap) {
return this.getLightmapWithDynamicLight(this.getDynamicLightLevel(pos), lightmap);
}

Expand Down Expand Up @@ -184,44 +200,10 @@ public int getLightmapWithDynamicLight(double dynamicLightLevel, int lightmap) {
* @return the dynamic light level at the specified position
*/
public double getDynamicLightLevel(@NotNull BlockPos pos) {
double result = 0;
this.lightSourcesLock.readLock().lock();
for (var lightSource : this.dynamicLightSources) {
result = maxDynamicLightLevel(pos, lightSource, result);
}
double light = this.engine.getDynamicLightLevel(pos);
this.lightSourcesLock.readLock().unlock();

return MathHelper.clamp(result, 0, 15);
}

/**
* Returns the dynamic light level generated by the light source at the specified position.
*
* @param pos the position
* @param lightSource the light source
* @param currentLightLevel the current surrounding dynamic light level
* @return the dynamic light level at the specified position
*/
public static double maxDynamicLightLevel(@NotNull BlockPos pos, @NotNull DynamicLightSource lightSource, double currentLightLevel) {
int luminance = lightSource.getLuminance();
if (luminance > 0) {
// Can't use Entity#squaredDistanceTo because of eye Y coordinate.
double dx = pos.getX() - lightSource.getDynamicLightX() + 0.5;
double dy = pos.getY() - lightSource.getDynamicLightY() + 0.5;
double dz = pos.getZ() - lightSource.getDynamicLightZ() + 0.5;

double distanceSquared = dx * dx + dy * dy + dz * dz;
// 7.75 because else we would have to update more chunks and that's not a good idea.
// 15 (max range for blocks) would be too much and a bit cheaty.
if (distanceSquared <= MAX_RADIUS_SQUARED) {
double multiplier = 1.0 - Math.sqrt(distanceSquared) / MAX_RADIUS;
double lightLevel = multiplier * (double) luminance;
if (lightLevel > currentLightLevel) {
return lightLevel;
}
}
}
return currentLightLevel;
return light;
}

/**
Expand All @@ -236,9 +218,7 @@ public void addLightSource(@NotNull DynamicLightSource lightSource) {
return;
if (this.containsLightSource(lightSource))
return;
this.lightSourcesLock.writeLock().lock();
this.dynamicLightSources.add(lightSource);
this.lightSourcesLock.writeLock().unlock();
}

/**
Expand All @@ -251,11 +231,7 @@ public boolean containsLightSource(@NotNull DynamicLightSource lightSource) {
if (!lightSource.getDynamicLightLevel().isClientSide())
return false;

boolean result;
this.lightSourcesLock.readLock().lock();
result = this.dynamicLightSources.contains(lightSource);
this.lightSourcesLock.readLock().unlock();
return result;
return this.dynamicLightSources.contains(lightSource);
}

/**
Expand All @@ -264,13 +240,7 @@ public boolean containsLightSource(@NotNull DynamicLightSource lightSource) {
* @return the number of dynamic light sources emitting light
*/
public int getLightSourcesCount() {
int result;

this.lightSourcesLock.readLock().lock();
result = this.dynamicLightSources.size();
this.lightSourcesLock.readLock().unlock();

return result;
return this.dynamicLightSources.size();
}

/**
Expand All @@ -279,39 +249,31 @@ public int getLightSourcesCount() {
* @param lightSource the light source to remove
*/
public void removeLightSource(@NotNull DynamicLightSource lightSource) {
this.lightSourcesLock.writeLock().lock();

var dynamicLightSources = this.dynamicLightSources.iterator();
DynamicLightSource it;
while (dynamicLightSources.hasNext()) {
it = dynamicLightSources.next();
if (it.equals(lightSource)) {
dynamicLightSources.remove();
lightSource.lambdynlights$scheduleTrackedChunksRebuild(Minecraft.getInstance().levelRenderer);
this.toClear.add(lightSource);
break;
}
}

this.lightSourcesLock.writeLock().unlock();
}

/**
* Clears light sources.
*/
public void clearLightSources() {
this.lightSourcesLock.writeLock().lock();

var dynamicLightSources = this.dynamicLightSources.iterator();
DynamicLightSource it;
while (dynamicLightSources.hasNext()) {
it = dynamicLightSources.next();
dynamicLightSources.remove();
if (it.getLuminance() > 0)
it.resetDynamicLight();
it.lambdynlights$scheduleTrackedChunksRebuild(Minecraft.getInstance().levelRenderer);
this.toClear.add(it);
}

this.lightSourcesLock.writeLock().unlock();
}

/**
Expand All @@ -320,8 +282,6 @@ public void clearLightSources() {
* @param filter the removal filter
*/
public void removeLightSources(@NotNull Predicate<DynamicLightSource> filter) {
this.lightSourcesLock.writeLock().lock();

var dynamicLightSources = this.dynamicLightSources.iterator();
DynamicLightSource it;
while (dynamicLightSources.hasNext()) {
Expand All @@ -330,12 +290,10 @@ public void removeLightSources(@NotNull Predicate<DynamicLightSource> filter) {
dynamicLightSources.remove();
if (it.getLuminance() > 0)
it.resetDynamicLight();
it.lambdynlights$scheduleTrackedChunksRebuild(Minecraft.getInstance().levelRenderer);
this.toClear.add(it);
break;
}
}

this.lightSourcesLock.writeLock().unlock();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* Represents a utility class for compatibility.
*
* @author LambdAurora
* @version 3.0.0
* @version 3.1.0
* @since 1.0.0
*/
public final class LambDynLightsCompat {
Expand All @@ -30,6 +30,10 @@ public static boolean isCanvasInstalled() {
return FabricLoader.getInstance().isModLoaded("canvas");
}

public static boolean isSodiumInstalled() {
return FabricLoader.getInstance().isModLoaded("sodium");
}

public static boolean isSodium05XInstalled() {
return FabricLoader.getInstance().getModContainer("sodium").map(mod -> {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* LambDynamicLights mixin plugin for conditional mixins.
*
* @author LambdAurora
* @version 3.0.1
* @version 3.1.0
* @since 1.0.0
*/
public class LambDynLightsMixinPlugin implements IMixinConfigPlugin {
Expand All @@ -33,6 +33,7 @@ public LambDynLightsMixinPlugin() {
this.conditionalMixins.put("dev.lambdaurora.lambdynlights.mixin.sodium.ArrayLightDataCacheMixin", sodium05XInstalled);
this.conditionalMixins.put("dev.lambdaurora.lambdynlights.mixin.sodium.FlatLightPipelineMixin", sodium05XInstalled);
this.conditionalMixins.put("dev.lambdaurora.lambdynlights.mixin.sodium.LightDataAccessMixin", sodium05XInstalled);
this.conditionalMixins.put("dev.lambdaurora.lambdynlights.mixin.sodium.SodiumOptionsGuiMixin", LambDynLightsCompat.isSodiumInstalled());

this.conditionalMixins.put("dev.lambdaurora.lambdynlights.mixin.DevModeMixin", LambDynLightsConstants.isDevMode());
}
Expand Down
Loading

0 comments on commit 7f0c1f5

Please sign in to comment.