From 7667f51cf366a41197b967290d4ff8ca5c00530f Mon Sep 17 00:00:00 2001 From: James Seibel Date: Tue, 14 Apr 2026 20:36:34 -0500 Subject: [PATCH] Add DhApiBlockColorOverrideEvent Could be helpful to !1240 --- .../render/blaze/BlazeDhMetaRenderer.java | 2 +- .../BlazeGenericObjectVertexContainer.java | 2 +- .../wrappers/texture/BlazeTextureWrapper.java | 2 +- .../wrappers/block/AbstractDhTintGetter.java | 2 +- .../wrappers/block/BlockStateWrapper.java | 16 +- .../block/ClientBlockStateColorCache.java | 168 ++++++++++-------- .../block/TextureAtlasSpriteWrapper.java | 2 +- .../minecraft/MinecraftRenderWrapper.java | 2 +- .../wrappers/world/ClientLevelWrapper.java | 2 +- coreSubProjects | 2 +- 10 files changed, 118 insertions(+), 82 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/BlazeDhMetaRenderer.java b/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/BlazeDhMetaRenderer.java index 003765afc..d5f47624c 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/BlazeDhMetaRenderer.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/BlazeDhMetaRenderer.java @@ -12,7 +12,7 @@ import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.render.RenderParams; -import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.coreapi.util.ColorUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/objects/BlazeGenericObjectVertexContainer.java b/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/objects/BlazeGenericObjectVertexContainer.java index c90414f6e..4b0fab8a9 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/objects/BlazeGenericObjectVertexContainer.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/objects/BlazeGenericObjectVertexContainer.java @@ -17,7 +17,7 @@ import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums; import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler; import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer; import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup; -import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.coreapi.util.ColorUtil; import org.lwjgl.opengl.GL32; import java.nio.ByteBuffer; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/wrappers/texture/BlazeTextureWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/wrappers/texture/BlazeTextureWrapper.java index e42ea30b5..30b09744f 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/wrappers/texture/BlazeTextureWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/render/blaze/wrappers/texture/BlazeTextureWrapper.java @@ -13,7 +13,7 @@ import com.mojang.blaze3d.textures.*; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.coreapi.util.ColorUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import java.util.OptionalDouble; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java index bed307bd0..cbf9c6529 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/AbstractDhTintGetter.java @@ -6,7 +6,7 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSour import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; -import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.coreapi.util.ColorUtil; import com.seibel.distanthorizons.core.util.FullDataPointUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java index 22ccd7dc6..3ee06fd92 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java @@ -25,7 +25,7 @@ import com.seibel.distanthorizons.common.wrappers.WrapperFactory; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.types.ConfigEntry; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.coreapi.util.ColorUtil; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; @@ -128,6 +128,7 @@ public class BlockStateWrapper implements IBlockStateWrapper private final boolean allowsBeaconBeamPassage; private final boolean isSolid; private final boolean isLiquid; + private final boolean allowApiColorOverride; /** null if this block can't tint beacons */ private final Color beaconTintColor; private final Color mapColor; @@ -225,6 +226,17 @@ public class BlockStateWrapper implements IBlockStateWrapper this.opacity = this.calculateOpacity(); } + // allow overriding if present + if (overrideEventParam != null + && overrideEventParam.getAllowApiColorOverride() != null) + { + this.allowApiColorOverride = overrideEventParam.getAllowApiColorOverride(); + } + else + { + this.allowApiColorOverride = false; + } + String lowerCaseSerial = this.serialString.toLowerCase(); @@ -682,6 +694,8 @@ public class BlockStateWrapper implements IBlockStateWrapper public boolean isBeaconTintBlock() { return this.beaconTintColor != null; } @Override public boolean allowsBeaconBeamPassage() { return this.allowsBeaconBeamPassage; } + @Override + public boolean allowApiColorOverride() { return this.allowApiColorOverride; } @Override public Color getMapColor() { return this.mapColor; } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java index 79259fc48..ee776f4b8 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java @@ -19,13 +19,17 @@ package com.seibel.distanthorizons.common.wrappers.block; +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; +import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper; +import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBlockColorOverrideEvent; import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; -import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.coreapi.util.ColorUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; +import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; @@ -187,8 +191,9 @@ public class ClientBlockStateColorCache }; // these are threadlocals since AbstractDhTintGetter use local variables to handle color queries - private static final ThreadLocal TintWithoutLevelOverrideGetter = ThreadLocal.withInitial(() -> new TintWithoutLevelOverrider()); - private static final ThreadLocal TintOverrideGetter = ThreadLocal.withInitial(() -> new TintGetterOverride()); + private static final ThreadLocal TintWithoutLevelOverrideGetter = ThreadLocal.withInitial(TintWithoutLevelOverrider::new); + private static final ThreadLocal TintOverrideGetter = ThreadLocal.withInitial(TintGetterOverride::new); + private static final ThreadLocal ColorOverrideEventParamGetter = ThreadLocal.withInitial(DhApiBlockColorOverrideEvent.EventParam::new); //endregion @@ -514,36 +519,33 @@ public class ClientBlockStateColorCache public int getColor(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos) { // only get the tint if the block needs to be tinted - if (!this.needPostTinting) - { - return this.baseColor; - } - - // don't try tinting blocks that don't support our method of tint getting - if (BROKEN_BLOCK_STATES.contains(this.blockState)) - { - return this.baseColor; - } - - - // attempt to get the tint int tintColor = AbstractDhTintGetter.INVALID_COLOR; - try + if (this.needPostTinting) { - // try to use the fast tint getter logic first - if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState)) + // don't try tinting blocks that don't support our method of tint getting + if (BROKEN_BLOCK_STATES.contains(this.blockState)) { - try + return this.baseColor; + } + + + // attempt to get the tint + try + { + // try to use the fast tint getter logic first + if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState)) { - TintWithoutLevelOverrider tintOverride = TintWithoutLevelOverrideGetter.get(); - tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper); - - // try using DH's cached tint values first if possible - tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos)); - if (tintColor == AbstractDhTintGetter.INVALID_COLOR) + try { - // one or more tint values weren't calculated, - // we need MC's color resolver + TintWithoutLevelOverrider tintOverride = TintWithoutLevelOverrideGetter.get(); + tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper); + + // try using DH's cached tint values first if possible + tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos)); + if (tintColor == AbstractDhTintGetter.INVALID_COLOR) + { + // one or more tint values weren't calculated, + // we need MC's color resolver #if MC_VER <= MC_1_21_11 tintColor = Minecraft.getInstance() .getBlockColors() @@ -552,53 +554,53 @@ public class ClientBlockStateColorCache McObjectConverter.Convert(blockPos), this.tintIndex); #else - BlockTintSource tintSource = Minecraft.getInstance() - .getBlockColors() - .getTintSource(this.blockState, this.tintIndex); - // a tint source may be null for blocks that don't actually need tinting - // in that case the base color should be sufficient - // Example: cherry blossom leaves - if (tintSource != null) - { - BlockPos mcPos = McObjectConverter.Convert(blockPos); - tintColor = tintSource.colorInWorld(this.blockState, tintOverride, mcPos); + BlockTintSource tintSource = Minecraft.getInstance() + .getBlockColors() + .getTintSource(this.blockState, this.tintIndex); + // a tint source may be null for blocks that don't actually need tinting + // in that case the base color should be sufficient + // Example: cherry blossom leaves + if (tintSource != null) + { + BlockPos mcPos = McObjectConverter.Convert(blockPos); + tintColor = tintSource.colorInWorld(this.blockState, tintOverride, mcPos); + if (tintColor == -1) + { + tintColor = tintSource.colorAsTerrainParticle(this.blockState, tintOverride, mcPos); + } + } + if (tintColor == -1) { - tintColor = tintSource.colorAsTerrainParticle(this.blockState, tintOverride, mcPos); + // no color found, use the base color + tintColor = AbstractDhTintGetter.INVALID_COLOR; } - } - - if (tintColor == -1) - { - // no color found, use the base color - tintColor = AbstractDhTintGetter.INVALID_COLOR; - } - - // save this color to speed up future queries - TintWithoutLevelOverrider.setStaticColor(this.blockStateWrapper, biomeWrapper, tintColor); - // try to get the blended color with this new information - tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos)); + + // save this color to speed up future queries + TintWithoutLevelOverrider.setStaticColor(this.blockStateWrapper, biomeWrapper, tintColor); + // try to get the blended color with this new information + tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos)); #endif + } } - } - catch (Exception e) - { + catch (Exception e) + { #if MC_VER <= MC_1_21_11 // this exception generally occurs if the tint requires other blocks besides itself LOGGER.debug("Unable to use ["+ TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e); BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState); #else - // only display the error once per block/biome type to reduce log spam - if (!BROKEN_BLOCK_STATES.contains(this.blockState)) - { - LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e); - BROKEN_BLOCK_STATES.add(this.blockState); - } + // only display the error once per block/biome type to reduce log spam + if (!BROKEN_BLOCK_STATES.contains(this.blockState)) + { + LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e); + BROKEN_BLOCK_STATES.add(this.blockState); + } #endif + } } - } - - // level-specific logic is only needed for MC 1.21.11 and older + + // level-specific logic is only needed for MC 1.21.11 and older #if MC_VER <= MC_1_21_11 // use the level logic only if requested if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState)) @@ -621,28 +623,48 @@ public class ClientBlockStateColorCache } } #endif - } - catch (Exception e) - { - // only display the error once per block/biome type to reduce log spam - if (!BROKEN_BLOCK_STATES.contains(this.blockState)) + } + catch (Exception e) { - LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e); - BROKEN_BLOCK_STATES.add(this.blockState); + // only display the error once per block/biome type to reduce log spam + if (!BROKEN_BLOCK_STATES.contains(this.blockState)) + { + LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e); + BROKEN_BLOCK_STATES.add(this.blockState); + } } } - + int returnColor; if (tintColor != AbstractDhTintGetter.INVALID_COLOR) { - return ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor); + returnColor = ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor); } else { // unable to get the tinted color, use the base color instead - return this.baseColor; + returnColor = this.baseColor; } + + + // only fire an API event if needed + // (this is done to reduce GC pressure and speed up color getting) + if (this.blockStateWrapper.allowApiColorOverride()) + { + DhApiBlockColorOverrideEvent.EventParam eventParam = ColorOverrideEventParamGetter.get(); + eventParam.update( + this.clientLevelWrapper, + this.blockStateWrapper, returnColor, + blockPos.getX(), blockPos.getY(), blockPos.getZ() + ); + ApiEventInjector.INSTANCE.fireAllEvents(DhApiBlockColorOverrideEvent.class, eventParam); + + // let the API user override this color + returnColor = eventParam.getColorAsInt(); + } + + return returnColor; } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TextureAtlasSpriteWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TextureAtlasSpriteWrapper.java index 81c441c30..f6a678afd 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TextureAtlasSpriteWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/TextureAtlasSpriteWrapper.java @@ -25,7 +25,7 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite; #if MC_VER < MC_1_17_1 #elif MC_VER < MC_1_21_3 #else -import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.coreapi.util.ColorUtil; import net.minecraft.client.renderer.texture.SpriteContents; #endif diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftRenderWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftRenderWrapper.java index adeef991f..440b4935f 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftRenderWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftRenderWrapper.java @@ -33,7 +33,7 @@ import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.enums.EDhDirection; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.coreapi.util.ColorUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper; #if MC_VER < MC_1_17_1 diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java index 14d20b086..2f42b98a7 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java @@ -48,7 +48,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; #if MC_VER < MC_1_21_3 import net.minecraft.world.phys.Vec3; #else -import com.seibel.distanthorizons.core.util.ColorUtil; +import com.seibel.distanthorizons.coreapi.util.ColorUtil; #endif #if MC_VER <= MC_1_21_10 diff --git a/coreSubProjects b/coreSubProjects index 1d368e3ad..61eaf43ba 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 1d368e3adcdeab24ee417ff7f56275007f585785 +Subproject commit 61eaf43ba0ece93bb9c61d8f7fa842ceb4c3ae78