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 a567e462b..b859cd780 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 @@ -689,7 +689,9 @@ public class ClientBlockStateColorCache //===============// //region - public int getColor(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos) + public int getColor( + BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos, + boolean allowApiOverride) { // only get the tint if the block needs to be tinted int tintColor = ClientBlockStateColorCache.INVALID_COLOR; @@ -853,14 +855,17 @@ public class ClientBlockStateColorCache } - // only fire an API event if needed - // (this is done to reduce GC pressure and speed up color getting) - if (this.blockStateWrapper.allowApiColorOverride()) + // only fire the API event if allowed + // (done to prevent infinite loops if called during by another color resolution event) + if (allowApiOverride + // if the API event is requested + // (this is done to reduce GC pressure and speed up color getting) + && this.blockStateWrapper.allowApiColorOverride()) { DhApiBlockColorOverrideEvent.EventParam eventParam = ColorOverrideEventParamGetter.get(); eventParam.update( - this.clientLevelWrapper, - this.blockStateWrapper, returnColor, + this.clientLevelWrapper, fullDataSource, + this.blockStateWrapper, biomeWrapper, returnColor, blockPos.getX(), blockPos.getY(), blockPos.getZ() ); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBlockColorOverrideEvent.class, eventParam); 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 d565c8ab8..0d8172031 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 @@ -1,21 +1,22 @@ package com.seibel.distanthorizons.common.wrappers.world; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper; +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; +import com.seibel.distanthorizons.api.objects.DhApiResult; +import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache; -import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; -import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.level.*; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; -import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper; @@ -32,7 +33,6 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkAccess; #endif import com.seibel.distanthorizons.core.logging.DhLogger; @@ -53,7 +53,6 @@ import java.util.function.Function; #elif MC_VER <= MC_1_20_4 import net.minecraft.world.level.chunk.ChunkStatus; #else -import net.minecraft.world.level.chunk.status.ChunkStatus; #endif #if MC_VER <= MC_1_12_2 @@ -88,6 +87,10 @@ public class ClientLevelWrapper implements IClientLevelWrapper private static final Minecraft MINECRAFT = Minecraft.getInstance(); #endif + private static final ThreadLocal MUTABLE_BLOCK_POS_THREAD_LOCAL = ThreadLocal.withInitial(DhBlockPosMutable::new); + + + #if MC_VER <= MC_1_12_2 private final WorldClient level; private final ConcurrentHashMap blockColorCacheByBlockState = new ConcurrentHashMap<>(); @@ -255,7 +258,9 @@ public class ClientLevelWrapper implements IClientLevelWrapper //region @Override - public int getBlockColor(DhBlockPos blockPos, IBiomeWrapper biome, FullDataSourceV2 fullDataSource, IBlockStateWrapper blockWrapper) + public int getBlockColor( + DhBlockPos blockWorldPos, IBiomeWrapper biome, FullDataSourceV2 fullDataSource, IBlockStateWrapper blockWrapper, + boolean allowApiOverride) { ClientBlockStateColorCache blockColorCache = this.blockColorCacheByBlockState.get(((BlockStateWrapper) blockWrapper).blockState); if (blockColorCache == null) @@ -265,7 +270,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper this.createCachedBlockColorCacheFunc); } - return blockColorCache.getColor((BiomeWrapper) biome, fullDataSource, blockPos); + return blockColorCache.getColor((BiomeWrapper) biome, fullDataSource, blockWorldPos, allowApiOverride); } @Override @@ -455,6 +460,45 @@ public class ClientLevelWrapper implements IClientLevelWrapper return this.dhLevel.getSaveStructure().getSaveFolder(this); } + @Override + public DhApiResult getBlockColorPreApi( + IDhApiBlockStateWrapper blockStateWrapper, + IDhApiBiomeWrapper biomeWrapper, + int blockWorldPosX, int blockWorldPosY, int blockWorldPosZ, + IDhApiFullDataSource dataSource) + { + // cast to core objects // + //region + + if(!(blockStateWrapper instanceof IBlockStateWrapper coreBlockStateWrapper)) + { + return DhApiResult.createFail("Unable to cast ["+blockStateWrapper.getClass()+"] to ["+IBlockStateWrapper.class+"]"); + } + + if(!(biomeWrapper instanceof IBiomeWrapper coreBiomeWrapper)) + { + return DhApiResult.createFail("Unable to cast ["+biomeWrapper.getClass()+"] to ["+IBiomeWrapper.class+"]"); + } + + if(!(dataSource instanceof FullDataSourceV2 coreDataSource)) + { + return DhApiResult.createFail("Unable to cast ["+dataSource.getClass()+"] to ["+FullDataSourceV2.class+"]"); + } + + //endregion + + + + // use a mutable thread local to reduce allocations slightly + DhBlockPosMutable blockWorldPos = MUTABLE_BLOCK_POS_THREAD_LOCAL.get(); + blockWorldPos.setX(blockWorldPosX); + blockWorldPos.setY(blockWorldPosY); + blockWorldPos.setZ(blockWorldPosZ); + + int color = this.getBlockColor(blockWorldPos, coreBiomeWrapper, coreDataSource, coreBlockStateWrapper, false); + return DhApiResult.createSuccess(ColorUtil.toColorObjARGB(color)); + } + //endregion diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java index 1a939a44a..6854c2b29 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java @@ -19,6 +19,7 @@ package com.seibel.distanthorizons.common.wrappers.world; +import java.awt.*; import java.io.File; import java.lang.ref.WeakReference; import java.util.Collections; @@ -26,21 +27,30 @@ import java.util.Map; import java.util.WeakHashMap; import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper; +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister; +import com.seibel.distanthorizons.api.objects.DhApiResult; +import com.seibel.distanthorizons.api.objects.data.IDhApiFullDataSource; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage; import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable; import com.seibel.distanthorizons.core.world.EWorldEnvironment; +import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; #if MC_VER <= MC_1_12_2 import net.minecraft.world.WorldServer; #else +import com.seibel.distanthorizons.coreapi.util.ColorUtil; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.ChunkAccess; @@ -80,6 +90,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper //==============// // constructors // //==============// + //region public static ServerLevelWrapper getWrapper(#if MC_VER <= MC_1_12_2 WorldServer #else ServerLevel #endif level) { @@ -104,11 +115,14 @@ public class ServerLevelWrapper implements IServerLevelWrapper this.KeyedLevelDimensionName = this.createKeyedLevelDimensionName(); } + //endregion + //==================// // instance methods // //==================// + //region @Override public File getMcSaveFolder() @@ -293,14 +307,28 @@ public class ServerLevelWrapper implements IServerLevelWrapper return this.dhLevel.getSaveStructure().getSaveFolder(this); } + @Override + public DhApiResult getBlockColorPreApi( + IDhApiBlockStateWrapper blockStateWrapper, + IDhApiBiomeWrapper biomeWrapper, + int blockWorldPosX, int blockWorldPosY, int blockWorldPosZ, + IDhApiFullDataSource dataSource) + { return DhApiResult.createFail("["+ServerLevelWrapper.class.getSimpleName()+"]'s cannot get block colors, please use a ["+ClientLevelWrapper.class.getSimpleName()+"] instead."); } + + //endregion //================// // base overrides // //================// + //region @Override public String toString() { return "Wrapped{" + this.level.toString() + "@" + this.getDhIdentifier() + "}"; } + //endregion + + + } diff --git a/coreSubProjects b/coreSubProjects index 946551249..492afa732 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 9465512491287b58091eb5946f30428748a612b0 +Subproject commit 492afa73285acca186a133c5d146dfeca7f74da3 diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestCustomColorEvent.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestCustomColorEvent.java index 66cab2399..729a3f466 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestCustomColorEvent.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/testing/TestCustomColorEvent.java @@ -1,13 +1,19 @@ package com.seibel.distanthorizons.fabric.testing; +import com.seibel.distanthorizons.api.DhApi; +import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; +import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBlockColorOverrideEvent; import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; +import com.seibel.distanthorizons.api.objects.DhApiResult; +import com.seibel.distanthorizons.common.wrappers.WrapperFactory; import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil; import java.awt.*; +import java.io.IOException; /** * @see TestBlockWrapperCreatedEvent @@ -26,7 +32,8 @@ public class TestCustomColorEvent extends DhApiBlockColorOverrideEvent //randomDatapointColors(eventParam); //randomPerBlockColors(eventParam); //blackWhitePositionStripe(eventParam); - positionRainbow(eventParam); + useWaterTint(eventParam); + //positionRainbow(eventParam); } /** each datapoint has a random color */ @@ -58,6 +65,36 @@ public class TestCustomColorEvent extends DhApiBlockColorOverrideEvent eventParam.setColor(r,g,b); } + /** every block will be rendered using water's color */ + private void useWaterTint(EventParam eventParam) + { + IDhApiBlockStateWrapper blockWrapper; + try + { + String blockNamespace = "minecraft:water"; // everything is a shade of blue (except swamps) + //String blockNamespace = "minecraft:oak_leaves"; // alternative example using oak leaves (everything is a shade of green) + blockWrapper = DhApi.Delayed.wrapperFactory.getDefaultBlockStateWrapper(blockNamespace, eventParam.getLevelWrapper()); + } + catch (IOException e) + { + blockWrapper = eventParam.getBlockStateWrapper(); + } + + DhApiResult result = eventParam.getLevelWrapper().getBlockColorPreApi( + blockWrapper, + eventParam.getBiomeWrapper(), + eventParam.getBlockPosX(), eventParam.getBlockPosY(), eventParam.getBlockPosZ(), + eventParam.getDataSource() + ); + if (!result.success) + { + // shouldn't happen, but just in case + return; + } + + eventParam.setColor(result.payload.getRed(), result.payload.getGreen(), result.payload.getBlue()); + } + private void blackWhitePositionStripe(EventParam eventParam) { // black-white stripes