add IDhApiLevelWrapper.getBlockColorPreApi()

This commit is contained in:
James Seibel
2026-05-18 19:59:56 -05:00
parent ab055f1a0e
commit 16e7254179
5 changed files with 130 additions and 16 deletions
@@ -689,7 +689,9 @@ public class ClientBlockStateColorCache
//===============// //===============//
//region //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 // only get the tint if the block needs to be tinted
int tintColor = ClientBlockStateColorCache.INVALID_COLOR; int tintColor = ClientBlockStateColorCache.INVALID_COLOR;
@@ -853,14 +855,17 @@ public class ClientBlockStateColorCache
} }
// only fire an API event if needed // only fire the API event if allowed
// (this is done to reduce GC pressure and speed up color getting) // (done to prevent infinite loops if called during by another color resolution event)
if (this.blockStateWrapper.allowApiColorOverride()) 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(); DhApiBlockColorOverrideEvent.EventParam eventParam = ColorOverrideEventParamGetter.get();
eventParam.update( eventParam.update(
this.clientLevelWrapper, this.clientLevelWrapper, fullDataSource,
this.blockStateWrapper, returnColor, this.blockStateWrapper, biomeWrapper, returnColor,
blockPos.getX(), blockPos.getY(), blockPos.getZ() blockPos.getX(), blockPos.getY(), blockPos.getZ()
); );
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBlockColorOverrideEvent.class, eventParam); ApiEventInjector.INSTANCE.fireAllEvents(DhApiBlockColorOverrideEvent.class, eventParam);
@@ -1,21 +1,22 @@
package com.seibel.distanthorizons.common.wrappers.world; package com.seibel.distanthorizons.common.wrappers.world;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; 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.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.BiomeWrapper;
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache; 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.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.level.*; import com.seibel.distanthorizons.core.level.*;
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; 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.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.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper; 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.core.BlockPos;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
#endif #endif
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -53,7 +53,6 @@ import java.util.function.Function;
#elif MC_VER <= MC_1_20_4 #elif MC_VER <= MC_1_20_4
import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.ChunkStatus;
#else #else
import net.minecraft.world.level.chunk.status.ChunkStatus;
#endif #endif
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
@@ -88,6 +87,10 @@ public class ClientLevelWrapper implements IClientLevelWrapper
private static final Minecraft MINECRAFT = Minecraft.getInstance(); private static final Minecraft MINECRAFT = Minecraft.getInstance();
#endif #endif
private static final ThreadLocal<DhBlockPosMutable> MUTABLE_BLOCK_POS_THREAD_LOCAL = ThreadLocal.withInitial(DhBlockPosMutable::new);
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
private final WorldClient level; private final WorldClient level;
private final ConcurrentHashMap<IBlockState, ClientBlockStateColorCache> blockColorCacheByBlockState = new ConcurrentHashMap<>(); private final ConcurrentHashMap<IBlockState, ClientBlockStateColorCache> blockColorCacheByBlockState = new ConcurrentHashMap<>();
@@ -255,7 +258,9 @@ public class ClientLevelWrapper implements IClientLevelWrapper
//region //region
@Override @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); ClientBlockStateColorCache blockColorCache = this.blockColorCacheByBlockState.get(((BlockStateWrapper) blockWrapper).blockState);
if (blockColorCache == null) if (blockColorCache == null)
@@ -265,7 +270,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
this.createCachedBlockColorCacheFunc); this.createCachedBlockColorCacheFunc);
} }
return blockColorCache.getColor((BiomeWrapper) biome, fullDataSource, blockPos); return blockColorCache.getColor((BiomeWrapper) biome, fullDataSource, blockWorldPos, allowApiOverride);
} }
@Override @Override
@@ -455,6 +460,45 @@ public class ClientLevelWrapper implements IClientLevelWrapper
return this.dhLevel.getSaveStructure().getSaveFolder(this); return this.dhLevel.getSaveStructure().getSaveFolder(this);
} }
@Override
public DhApiResult<Color> 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 //endregion
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.common.wrappers.world; package com.seibel.distanthorizons.common.wrappers.world;
import java.awt.*;
import java.io.File; import java.io.File;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Collections; import java.util.Collections;
@@ -26,21 +27,30 @@ import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType; 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.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.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config; 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.level.IDhLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage; import com.seibel.distanthorizons.core.network.messages.base.LevelInitMessage;
import com.seibel.distanthorizons.core.pos.DhChunkPos; 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.world.EWorldEnvironment;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
#if MC_VER <= MC_1_12_2 #if MC_VER <= MC_1_12_2
import net.minecraft.world.WorldServer; import net.minecraft.world.WorldServer;
#else #else
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
@@ -80,6 +90,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper
//==============// //==============//
// constructors // // constructors //
//==============// //==============//
//region
public static ServerLevelWrapper getWrapper(#if MC_VER <= MC_1_12_2 WorldServer #else ServerLevel #endif level) 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(); this.KeyedLevelDimensionName = this.createKeyedLevelDimensionName();
} }
//endregion
//==================// //==================//
// instance methods // // instance methods //
//==================// //==================//
//region
@Override @Override
public File getMcSaveFolder() public File getMcSaveFolder()
@@ -293,14 +307,28 @@ public class ServerLevelWrapper implements IServerLevelWrapper
return this.dhLevel.getSaveStructure().getSaveFolder(this); return this.dhLevel.getSaveStructure().getSaveFolder(this);
} }
@Override
public DhApiResult<Color> 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 // // base overrides //
//================// //================//
//region
@Override @Override
public String toString() { return "Wrapped{" + this.level.toString() + "@" + this.getDhIdentifier() + "}"; } public String toString() { return "Wrapped{" + this.level.toString() + "@" + this.getDhIdentifier() + "}"; }
//endregion
} }
@@ -1,13 +1,19 @@
package com.seibel.distanthorizons.fabric.testing; 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.abstractEvents.DhApiBlockColorOverrideEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiEventParam; 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.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.coreapi.util.ColorUtil; import com.seibel.distanthorizons.coreapi.util.ColorUtil;
import java.awt.*; import java.awt.*;
import java.io.IOException;
/** /**
* @see TestBlockWrapperCreatedEvent * @see TestBlockWrapperCreatedEvent
@@ -26,7 +32,8 @@ public class TestCustomColorEvent extends DhApiBlockColorOverrideEvent
//randomDatapointColors(eventParam); //randomDatapointColors(eventParam);
//randomPerBlockColors(eventParam); //randomPerBlockColors(eventParam);
//blackWhitePositionStripe(eventParam); //blackWhitePositionStripe(eventParam);
positionRainbow(eventParam); useWaterTint(eventParam);
//positionRainbow(eventParam);
} }
/** each datapoint has a random color */ /** each datapoint has a random color */
@@ -58,6 +65,36 @@ public class TestCustomColorEvent extends DhApiBlockColorOverrideEvent
eventParam.setColor(r,g,b); 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<Color> 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) private void blackWhitePositionStripe(EventParam eventParam)
{ {
// black-white stripes // black-white stripes