From 1cc497f44a48cfc46ef09ec129c41a1d9ceb87b7 Mon Sep 17 00:00:00 2001 From: spiralhalo Date: Mon, 8 Jan 2024 03:42:45 +0700 Subject: [PATCH] Let pipeline disallow virtual lights, more robust reload - More robust LightLevel and EntityLightTracker reload - More robust CanvasState requireReload --- .../grondag/canvas/apiimpl/CanvasState.java | 14 ++-- .../grondag/canvas/config/ConfigData.java | 2 +- .../light/color/EntityLightTracker.java | 18 ++--- .../canvas/light/color/LightLevel.java | 72 +++++++++++++++---- .../pipeline/config/ColoredLightsConfig.java | 2 + .../resources/assets/canvas/lang/en_us.json | 2 +- 6 files changed, 82 insertions(+), 28 deletions(-) diff --git a/src/main/java/grondag/canvas/apiimpl/CanvasState.java b/src/main/java/grondag/canvas/apiimpl/CanvasState.java index 785a3e50b..1323a0a93 100644 --- a/src/main/java/grondag/canvas/apiimpl/CanvasState.java +++ b/src/main/java/grondag/canvas/apiimpl/CanvasState.java @@ -20,6 +20,8 @@ package grondag.canvas.apiimpl; +import java.util.Objects; + import net.minecraft.client.Minecraft; import net.minecraft.client.resources.language.I18n; @@ -69,16 +71,18 @@ public static void recompile() { private static int loopCounter = 0; private static boolean recompilePipeline() { - final boolean prevColorLightsState = Pipeline.coloredLightsEnabled(); - final boolean prevAdvancedCullingState = Pipeline.advancedTerrainCulling(); + final var prev_coloredLightsConfig = Pipeline.config().coloredLights; + final boolean coloredLights_wasDisabled = !Pipeline.coloredLightsEnabled(); + final boolean advancedCulling_wasDisabled = !Pipeline.advancedTerrainCulling(); PipelineLoader.reload(Minecraft.getInstance().getResourceManager()); PipelineManager.reload(); - final boolean coloredLightsChanged = Pipeline.coloredLightsEnabled() && !prevColorLightsState; - final boolean requireCullingRebuild = Pipeline.advancedTerrainCulling() && !prevAdvancedCullingState; + final boolean coloredLightsConfigChanged = !Objects.equals(Pipeline.config().coloredLights, prev_coloredLightsConfig); + final boolean coloredLights_requiresRebuild = Pipeline.coloredLightsEnabled() && (coloredLightsConfigChanged || coloredLights_wasDisabled); + final boolean culling_requiresRebuild = Pipeline.advancedTerrainCulling() && advancedCulling_wasDisabled; - return coloredLightsChanged || requireCullingRebuild; + return coloredLights_requiresRebuild || culling_requiresRebuild; } private static void recompile(boolean wasReloaded) { diff --git a/src/main/java/grondag/canvas/config/ConfigData.java b/src/main/java/grondag/canvas/config/ConfigData.java index 54ec8176b..d20ec6409 100644 --- a/src/main/java/grondag/canvas/config/ConfigData.java +++ b/src/main/java/grondag/canvas/config/ConfigData.java @@ -57,7 +57,7 @@ class ConfigData { boolean semiFlatLighting = true; @Comment("Enable colored block lights on pipelines that support it. Replaces vanilla lighting but only visually.") boolean coloredLights = false; - @Comment("Enable entity as dynamic light sources. Requires colored lights.") + @Comment("Enable entity as dynamic light sources. Requires colored lights and supporting pipeline.") boolean entityLightSource = false; // TWEAKS diff --git a/src/main/java/grondag/canvas/light/color/EntityLightTracker.java b/src/main/java/grondag/canvas/light/color/EntityLightTracker.java index f660124e9..f4668bac2 100644 --- a/src/main/java/grondag/canvas/light/color/EntityLightTracker.java +++ b/src/main/java/grondag/canvas/light/color/EntityLightTracker.java @@ -77,15 +77,15 @@ public static void levelRemovesEntity(int id) { } } - void reload() { + void reload(boolean clearLights) { requiresInitialization = true; // might be called twice due to multiple hook (setLevel and allChanged). idempotent. - removeAll(); + removeAll(clearLights); } - void close(boolean lightLevelIsClosing) { - if (!lightLevelIsClosing) { - removeAll(); + void close(boolean clear) { + if (clear) { + removeAll(true); } if (INSTANCE == this) { @@ -93,10 +93,12 @@ void close(boolean lightLevelIsClosing) { } } - private void removeAll() { + private void removeAll(boolean clearLights) { // see notes on reload() - for (var entity:entities.values()) { - entity.removeLight(); + if (clearLights) { + for (var entity : entities.values()) { + entity.removeLight(); + } } entities.clear(); diff --git a/src/main/java/grondag/canvas/light/color/LightLevel.java b/src/main/java/grondag/canvas/light/color/LightLevel.java index e2c7fdfea..5d0e21e99 100644 --- a/src/main/java/grondag/canvas/light/color/LightLevel.java +++ b/src/main/java/grondag/canvas/light/color/LightLevel.java @@ -33,6 +33,7 @@ import grondag.canvas.CanvasMod; import grondag.canvas.config.Configurator; +import grondag.canvas.pipeline.Pipeline; class LightLevel implements LightLevelAccess { private BlockAndTintGetter baseLevel = null; @@ -42,6 +43,13 @@ class LightLevel implements LightLevelAccess { private final LongArrayFIFOQueue virtualQueue = new LongArrayFIFOQueue(); private final ObjectOpenHashSet virtualCheckQueue = new ObjectOpenHashSet<>(); + private static final Operator DO_NOTHING = (pos, light) -> { }; + private static final Getter GET_ZERO = pos -> (short) 0; + + private Operator placer = DO_NOTHING; + private Operator remover = DO_NOTHING; + private Getter getter = GET_ZERO; + LightLevel() { reload(); @@ -50,19 +58,38 @@ class LightLevel implements LightLevelAccess { } public void reload() { - if (Configurator.entityLightSource) { + assert Pipeline.config().coloredLights != null; + + final boolean virtualAllowed = Pipeline.config().coloredLights.allowVirtual; + + if (Configurator.entityLightSource && virtualAllowed) { if (entityLightTracker == null) { entityLightTracker = new EntityLightTracker(this); } else { - entityLightTracker.reload(); + // no need to clear as we are nuking everything + entityLightTracker.reload(false); } } else { if (entityLightTracker != null) { + // no need to clear as we are nuking everything entityLightTracker.close(false); } entityLightTracker = null; } + + // NB: implementations are expected to repopulate every time chunk is reloaded + virtualLights.clear(); + + if (virtualAllowed) { + placer = PLACE_VIRTUAL; + remover = REMOVE_VIRTUAL; + getter = GET_VIRTUAL; + } else { + placer = DO_NOTHING; + remover = DO_NOTHING; + getter = GET_ZERO; + } } void updateOnStartFrame(ClientLevel level) { @@ -70,7 +97,7 @@ void updateOnStartFrame(ClientLevel level) { baseLevel = level; if (entityLightTracker != null) { - entityLightTracker.reload(); + entityLightTracker.reload(true); } } @@ -89,26 +116,34 @@ public BlockAndTintGetter level() { @Override public short getRegistered(BlockPos pos) { var registered = baseLevel == null ? 0 : LightRegistry.get(baseLevel.getBlockState(pos)); - return combineWithBlockLight(registered, getVirtualLight(pos)); + return combineWithBlockLight(registered, getter.apply(pos)); } @Override public short getRegistered(BlockPos pos, @Nullable BlockState state) { // MAINTENANCE NOTICE: this function is a special casing of getRegistered(BlockPos) var registered = state != null ? LightRegistry.get(state) : (baseLevel == null ? 0 : LightRegistry.get(baseLevel.getBlockState(pos))); - return combineWithBlockLight(registered, getVirtualLight(pos)); + return combineWithBlockLight(registered, getter.apply(pos)); } @Override public void placeVirtualLight(BlockPos blockPos, short light) { + placer.apply(blockPos, light); + } + + @Override + public void removeVirtualLight(BlockPos blockPos, short light) { + remover.apply(blockPos, light); + } + + private final Operator PLACE_VIRTUAL = (blockPos, light) -> { final long pos = blockPos.asLong(); final var list = virtualLights.computeIfAbsent(pos, l -> new ShortArrayList()); list.add(encodeVirtualLight(light)); virtualQueue.enqueue(pos); - } + }; - @Override - public void removeVirtualLight(BlockPos blockPos, short light) { + private final Operator REMOVE_VIRTUAL = (blockPos, light) -> { final long pos = blockPos.asLong(); final var list = virtualLights.get(pos); final int i = list == null ? -1 : list.indexOf(encodeVirtualLight(light)); @@ -117,16 +152,17 @@ public void removeVirtualLight(BlockPos blockPos, short light) { list.removeShort(i); virtualQueue.enqueue(pos); } - } + }; void close() { if (entityLightTracker != null) { - entityLightTracker.close(true); + // no need to clear as we are nuking everything + entityLightTracker.close(false); entityLightTracker = null; } } - private short getVirtualLight(BlockPos blockPos) { + private final Getter GET_VIRTUAL = blockPos -> { ShortArrayList lights = virtualLights.get(blockPos.asLong()); if (lights != null) { @@ -139,8 +175,8 @@ private short getVirtualLight(BlockPos blockPos) { return combined; } - return 0; - } + return (short) 0; + }; private void updateInner() { while (!virtualQueue.isEmpty()) { @@ -172,4 +208,14 @@ public static short encodeVirtualLight(short light) { private static short combineWithBlockLight(short block, short virtual) { return LightOp.makeEmitter(LightOp.max(block, virtual)); } + + @FunctionalInterface + private interface Operator { + void apply(BlockPos pos, short light); + } + + @FunctionalInterface + private interface Getter { + short apply(BlockPos pos); + } } diff --git a/src/main/java/grondag/canvas/pipeline/config/ColoredLightsConfig.java b/src/main/java/grondag/canvas/pipeline/config/ColoredLightsConfig.java index 6936c887e..a9a676a89 100644 --- a/src/main/java/grondag/canvas/pipeline/config/ColoredLightsConfig.java +++ b/src/main/java/grondag/canvas/pipeline/config/ColoredLightsConfig.java @@ -27,11 +27,13 @@ public class ColoredLightsConfig extends AbstractConfig { public final boolean enabled; + public final boolean allowVirtual; public final boolean useOcclusionData; protected ColoredLightsConfig(ConfigContext ctx, JsonObject config) { super(ctx); enabled = ctx.dynamic.getBoolean(config, "enabled", true); + allowVirtual = ctx.dynamic.getBoolean(config, "allowVirtual", true); useOcclusionData = ctx.dynamic.getBoolean(config, "useOcclusionData", false); } diff --git a/src/main/resources/assets/canvas/lang/en_us.json b/src/main/resources/assets/canvas/lang/en_us.json index 8724e6228..d16540aae 100644 --- a/src/main/resources/assets/canvas/lang/en_us.json +++ b/src/main/resources/assets/canvas/lang/en_us.json @@ -56,7 +56,7 @@ "config.canvas.value.colored_lights": "Colored Lights", "config.canvas.help.colored_lights": "Enable colored block lights on pipelines that support it. Replaces vanilla lighting but only visually.", "config.canvas.value.entity_light_source": "Entity Light Source", - "config.canvas.help.entity_light_source": "Enable entity as dynamic light sources. Requires colored lights.", + "config.canvas.help.entity_light_source": "Enable entity as dynamic light sources. Requires colored lights and supporting pipeline.", "config.canvas.enum.ao_mode.normal": "Vanilla", "config.canvas.enum.ao_mode.subtle_always": "Subtle", "config.canvas.enum.ao_mode.subtle_block_light": "Subtle Torchlit",