diff --git a/common/src/main/java/com/seibel/lod/common/Config.java b/common/src/main/java/com/seibel/lod/common/Config.java index f2138952e..28c610419 100644 --- a/common/src/main/java/com/seibel/lod/common/Config.java +++ b/common/src/main/java/com/seibel/lod/common/Config.java @@ -166,6 +166,16 @@ public class Config @ConfigAnnotations.Entry public static boolean useExtendedNearClipPlane = IAdvancedGraphics.USE_EXTENDED_NEAR_CLIP_PLANE_DEFAULT; + @ConfigAnnotations.FileComment + public static String _brightnessMultiplier = IAdvancedGraphics.BRIGHTNESS_MULTIPLIER_DESC; + @ConfigAnnotations.Entry + public static double brightnessMultiplier = IAdvancedGraphics.BRIGHTNESS_MULTIPLIER_DEFAULT; + + @ConfigAnnotations.FileComment + public static String _saturationMultiplier = IAdvancedGraphics.SATURATION_MULTIPLIER_DESC; + @ConfigAnnotations.Entry + public static double saturationMultiplier = IAdvancedGraphics.SATURATION_MULTIPLIER_DEFAULT; + /* @ConfigAnnotations.FileComment public static String _backsideCullingRange = IAdvancedGraphics.VANILLA_CULLING_RANGE_DESC; diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/McObjectConverter.java b/common/src/main/java/com/seibel/lod/common/wrappers/McObjectConverter.java index 154e402bc..9daeee9ba 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/McObjectConverter.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/McObjectConverter.java @@ -24,7 +24,9 @@ import java.nio.FloatBuffer; import com.mojang.math.Matrix4f; import com.seibel.lod.core.enums.LodDirection; import com.seibel.lod.core.objects.math.Mat4f; +import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper; +import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; /** @@ -48,17 +50,27 @@ public class McObjectConverter static final Direction[] directions; + static final LodDirection[] lodDirections; static { LodDirection[] lodDirs = LodDirection.values(); directions = new Direction[lodDirs.length]; + lodDirections = new LodDirection[lodDirs.length]; for (LodDirection lodDir : lodDirs) { - directions[lodDir.ordinal()] = Direction.byName(lodDir.name()); - } + Direction dir = Direction.byName(lodDir.name()); + directions[lodDir.ordinal()] = dir; + lodDirections[dir.ordinal()] = lodDir; + } } - - + + public static BlockPos Convert(AbstractBlockPosWrapper wrappedPos) { + return new BlockPos(wrappedPos.getX(),wrappedPos.getY(), wrappedPos.getZ()); + } + public static Direction Convert(LodDirection lodDirection) { return directions[lodDirection.ordinal()]; } + public static LodDirection Convert(Direction direction) { + return lodDirections[direction.ordinal()]; + } } diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailMap.java b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailMap.java index bc57b5f98..65c088381 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailMap.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailMap.java @@ -1,286 +1,26 @@ package com.seibel.lod.common.wrappers.block; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; - -import com.seibel.lod.core.api.ApiShared; -import com.seibel.lod.core.util.ColorUtil; -import com.seibel.lod.core.wrapperInterfaces.block.BlockDetail; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.FlowerBlock; -import net.minecraft.world.level.block.LeavesBlock; -import net.minecraft.world.level.block.LiquidBlock; -import net.minecraft.world.level.block.RenderShape; -import net.minecraft.world.level.block.RotatedPillarBlock; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.shapes.VoxelShape; + +import java.util.concurrent.ConcurrentHashMap; public class BlockDetailMap { - public static final int FLOWER_COLOR_SCALE = 5; - - public static final Random random = new Random(0); - - //TODO: Perhaps make this not just use the first frame? - //FIXME: Stuff is wrong. - private static int calculateColorFromTexture(TextureAtlasSprite texture, boolean useFlowerScaling, boolean useFastLeaf) { - - int count = 0; - double alpha = 0; - double red = 0; - double green = 0; - double blue = 0; - int tempColor; - - { - // textures normally use u and v instead of x and y - for (int u = 0; u < texture.getWidth(); u++) - { - for (int v = 0; v < texture.getHeight(); v++) - { - //note: Minecraft color format is: 0xAA BB GG RR - //________ DH mod color format is: 0xAA RR GG BB - //OpenGL RGBA format native order: 0xRR GG BB AA - //_ OpenGL RGBA format Java Order: 0xAA BB GG RR - tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v); - - double r = ((tempColor & 0x000000FF) )/255.; - double g = ((tempColor & 0x0000FF00) >>> 8)/255.; - double b = ((tempColor & 0x00FF0000) >>> 16)/255.; - double a = ((tempColor & 0xFF000000) >>> 24)/255.; - int scale = 1; - - if (useFastLeaf) { - r *= a; - g *= a; - b *= a; - a = 1.; - } else if (a==0.) { - continue; - } else if (useFlowerScaling && (g+0.1 biomeDetailMap = null; - BlockDetail blockDetail; - BlockDetail defaultTintedDetail = null; - boolean requireResolving; - @SuppressWarnings("unused") - boolean requireShade; //TODO: Add back using this in renderer - @SuppressWarnings("unused") - boolean scaleFlowerColor; //FIXME: Do I need to scale the tint color??? - int tintIndex; - - static boolean isBlockToBeAvoid(Block b) { - for (Block bta : BLOCK_TO_AVOID) - if (bta==b) return true; - return false; - } - - static boolean hasNoCollision(BlockState bs, BlockPos pos, LevelReader getter) { - if (!bs.getFluidState().isEmpty() || bs.getBlock() instanceof LiquidBlock) // Is blockState a fluid? - return false; - if (bs.getCollisionShape(getter, pos).isEmpty()) - return true; - return false; - } - static boolean hasOnlyNonFullFace(BlockState bs, BlockPos pos, LevelReader getter) { - if (!bs.getFluidState().isEmpty() || bs.getBlock() instanceof LiquidBlock) // Is blockState a fluid? - return false; - VoxelShape voxelShape = bs.getShape(getter, pos); - if (voxelShape.isEmpty()) return true; - AABB bbox = voxelShape.bounds(); - double xWidth = (bbox.maxX - bbox.minX); - double yWidth = (bbox.maxY - bbox.minY); - double zWidth = (bbox.maxZ - bbox.minZ); - return xWidth < 1 && zWidth < 1 && yWidth < 1; - } - - static BlockDetailCache make(BlockState bs, BlockPos pos, LevelReader getter) { - boolean noCol, nonFull, canOcclude; - if(!bs.getFluidState().isEmpty()) { - bs = bs.getFluidState().createLegacyBlock(); - FluidState fs = bs.getFluidState(); - fs.getType(); - noCol = false; - nonFull = false; - canOcclude = false; - BlockDetailCache result = new BlockDetailCache(fs); - //ApiShared.LOGGER.info(fs.toString()+" = ["+result+"]"); - return result; - } else { - if (bs.getRenderShape() != RenderShape.MODEL) return NULL_BLOCK_DETAIL; - if (isBlockToBeAvoid(bs.getBlock())) return NULL_BLOCK_DETAIL; - //BlocksToAvoid toAvoid = CONFIG.client().worldGenerator().getBlocksToAvoid(); - noCol = hasNoCollision(bs, pos, getter); - nonFull = hasOnlyNonFullFace(bs, pos, getter); - canOcclude = bs.canOcclude(); - List quads = null; - for (Direction direction : DIRECTION_ORDER) - { - quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().getBlockModel(bs).getQuads(bs, direction, random); - if (!quads.isEmpty() && !(bs.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP)) - break; - }; - if (quads == null || quads.isEmpty()) return NULL_BLOCK_DETAIL; - BlockDetailCache result = new BlockDetailCache(canOcclude, noCol, nonFull, quads.get(0), - bs.getBlock() instanceof FlowerBlock, bs.getBlock() instanceof LeavesBlock); - // ApiShared.LOGGER.info(bs.toString()+" = ["+result+"]"); - return result; - } - } - - BlockDetailCache(boolean isFullBlock, boolean noCol, boolean nonFull, BakedQuad quad, boolean useFlowerScaling, boolean useFastLeaf) { - requireResolving = quad.isTinted(); - requireShade = quad.isShade(); - tintIndex = quad.getTintIndex(); - scaleFlowerColor = useFlowerScaling; - blockDetail = new BlockDetail(calculateColorFromTexture(quad.getSprite(), useFlowerScaling, useFastLeaf), isFullBlock, noCol, nonFull); - if (quad.isTinted()) biomeDetailMap = new ConcurrentHashMap(); - } - - BlockDetailCache(FluidState fluid) { - requireResolving = true; // TODO: Maybe in the future recheck that there really is no way to see if a fluid needs tinting - requireShade = false; - tintIndex = 0; // Vanilla doesn't use this index currently. (Checked at 1.18.X, See BlockColors.class) - scaleFlowerColor = false; - TextureAtlasSprite text = Minecraft.getInstance().getModelManager().getBlockModelShaper().getBlockModel(fluid.createLegacyBlock()).getParticleIcon(); - blockDetail = new BlockDetail(calculateColorFromTexture(text, false, false), true, false, false); - biomeDetailMap = new ConcurrentHashMap(); - } - - private BlockDetailCache() - { - //DUMMY CREATOR - } - - BlockDetail getResolvedBlockDetail(BlockState bs, int x, int y, int z, LevelReader getter) { - if (!requireResolving) return blockDetail; - BlockPos pos = new BlockPos(x,y,z); - Biome biome = getter.getBiome(pos); - BlockDetail tintDetail = biomeDetailMap.get(biome); - if (tintDetail == null) { - if (!bs.getFluidState().isEmpty()) bs = bs.getFluidState().createLegacyBlock(); - BlockColors bc = Minecraft.getInstance().getBlockColors(); - int tintColor = bc.getColor(bs, getter, pos, tintIndex); - tintColor = ColorUtil.multiplyARGBwithRGB(blockDetail.color, tintColor); - tintDetail = new BlockDetail(tintColor, blockDetail.isFullBlock, - blockDetail.hasNoCollision, blockDetail.hasOnlyNonFullFace); - BlockDetail tintDetailCAS = biomeDetailMap.putIfAbsent(biome, tintDetail); - if (tintDetailCAS != null) tintDetail = tintDetailCAS; - } - return tintDetail; - } - - // Note: this one won't resolve biome based or pos based colors. (Kinda like GUI block icons) - BlockDetail getResolvedBlockDetail(BlockState bs) { - if (!requireResolving) return blockDetail; - if (defaultTintedDetail != null) return defaultTintedDetail; - - BlockColors bc = Minecraft.getInstance().getBlockColors(); - if (!bs.getFluidState().isEmpty()) bs = bs.getFluidState().createLegacyBlock(); - int tintColor = bc.getColor(bs, null, null, tintIndex); - if (tintColor == -1) { - defaultTintedDetail = blockDetail; - } - else { - defaultTintedDetail = new BlockDetail(ColorUtil.multiplyARGBwithRGB(blockDetail.color, tintColor), - blockDetail.isFullBlock, blockDetail.hasNoCollision, blockDetail.hasOnlyNonFullFace); - } - return defaultTintedDetail; - } - - @Override - public String toString() { - return "[BlockDetail: "+blockDetail+", RequireResolving: "+requireResolving+", requireShade: "+requireShade+", scaleFlowerColor: "+scaleFlowerColor+"]"; - } - - } - - - - private static ConcurrentHashMap map = new ConcurrentHashMap(); + private static ConcurrentHashMap map = new ConcurrentHashMap(); private BlockDetailMap() {} - private static BlockDetailCache getOrMakeBlockDetailCache(BlockState bs, BlockPos pos, LevelReader getter) { - BlockDetailCache cache = map.get(bs); + public static BlockDetailWrapper getOrMakeBlockDetailCache(BlockState bs, BlockPos pos, LevelReader getter) { + BlockDetailWrapper cache = map.get(bs); if (cache != null) return cache; if (bs.getFluidState().isEmpty()) { - cache = BlockDetailCache.make(bs, pos, getter); + cache = BlockDetailWrapper.make(bs, pos, getter); } else { - cache = BlockDetailCache.make(bs.getFluidState().createLegacyBlock(), pos, getter); + cache = BlockDetailWrapper.make(bs.getFluidState().createLegacyBlock(), pos, getter); } - BlockDetailCache cacheCAS = map.putIfAbsent(bs, cache); + BlockDetailWrapper cacheCAS = map.putIfAbsent(bs, cache); return cacheCAS==null ? cache : cacheCAS; } - - - // Return null means skip the block - public static BlockDetail getBlockDetail(BlockState bs) { - BlockDetailCache cache = getOrMakeBlockDetailCache(bs, new BlockPos(0, 0, 0), null); - if (cache == BlockDetailCache.NULL_BLOCK_DETAIL) return null; - return cache.getResolvedBlockDetail(bs); - } - - // Return null means skip the block - public static BlockDetail getBlockDetailWithCompleteTint(BlockState bs, int x, int y, int z, LevelReader tintGetter) { - BlockDetailCache cache = getOrMakeBlockDetailCache(bs, new BlockPos(x,y,z), tintGetter); - if (cache == BlockDetailCache.NULL_BLOCK_DETAIL) return null; - return cache.getResolvedBlockDetail(bs, x, y, z, tintGetter); - } } diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailWrapper.java b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailWrapper.java new file mode 100644 index 000000000..b05eb92d5 --- /dev/null +++ b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailWrapper.java @@ -0,0 +1,284 @@ +package com.seibel.lod.common.wrappers.block; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import com.seibel.lod.common.wrappers.McObjectConverter; +import com.seibel.lod.common.wrappers.chunk.ChunkWrapper; +import com.seibel.lod.core.enums.LodDirection; +import com.seibel.lod.core.util.ColorUtil; +import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper; +import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper; +import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.FlowerBlock; +import net.minecraft.world.level.block.LeavesBlock; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.RotatedPillarBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class BlockDetailWrapper extends IBlockDetailWrapper +{ + public static final int FLOWER_COLOR_SCALE = 5; + + public static final Random random = new Random(0); + + enum ColorMode { + Default, + Flower, + Leaves; + static ColorMode getColorMode(Block b) { + if (b instanceof LeavesBlock) return Leaves; + if (b instanceof FlowerBlock) return Flower; + return Default; + } + } + //TODO: Perhaps make this not just use the first frame? + private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) { + + int count = 0; + double alpha = 0; + double red = 0; + double green = 0; + double blue = 0; + int tempColor; + + { + // textures normally use u and v instead of x and y + for (int u = 0; u < texture.getWidth(); u++) + { + for (int v = 0; v < texture.getHeight(); v++) + { + //note: Minecraft color format is: 0xAA BB GG RR + //________ DH mod color format is: 0xAA RR GG BB + //OpenGL RGBA format native order: 0xRR GG BB AA + //_ OpenGL RGBA format Java Order: 0xAA BB GG RR + tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v); + + double r = ((tempColor & 0x000000FF) )/255.; + double g = ((tempColor & 0x0000FF00) >>> 8)/255.; + double b = ((tempColor & 0x00FF0000) >>> 16)/255.; + double a = ((tempColor & 0xFF000000) >>> 24)/255.; + int scale = 1; + + if (colorMode == ColorMode.Leaves) { + r *= a; + g *= a; + b *= a; + a = 1.; + } else if (a==0.) { + continue; + } else if (colorMode == ColorMode.Flower && (g+0.1 quads = null; + for (Direction direction : DIRECTION_ORDER) + { + quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). + getBlockModel(state).getQuads(state, direction, random); + if (!quads.isEmpty() && + !(state.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP)) + break; + }; + if (quads != null && !quads.isEmpty()) { + needPostTinting = quads.get(0).isTinted(); + needShade = quads.get(0).isShade(); + tintIndex = quads.get(0).getTintIndex(); + baseColor = calculateColorFromTexture(quads.get(0).getSprite(), + ColorMode.getColorMode(state.getBlock())); + } + } else { // Liquid Block + + needPostTinting = true; + needShade = false; + tintIndex = 0; + baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state), + ColorMode.getColorMode(state.getBlock())); + + } + isColorResolved = true; + } + + + + @Override + public int getAndResolveFaceColor(LodDirection dir, IChunkWrapper chunk, AbstractBlockPosWrapper blockPos) + { + // FIXME: impl per-face colors + resolveColors(); + if (!needPostTinting) return baseColor; + int tintColor = Minecraft.getInstance().getBlockColors() + .getColor(state, ((ChunkWrapper)chunk).getColorResolver(), + McObjectConverter.Convert(blockPos), tintIndex); + if (tintColor == -1) return baseColor; + return ColorUtil.multiplyARGBwithRGB(baseColor, tintColor); + } + + @Override + public boolean hasFaceCullingFor(LodDirection dir) + { + resolveShapes(); + return !dontOccludeFaces[dir.ordinal()]; + } + + @Override + public boolean hasNoCollision() + { + resolveShapes(); + return noCollision; + } + + @Override + public boolean noFaceIsFullFace() + { + resolveShapes(); + return noFullFace; + } + + @Override + public String serialize() + { + // FIXME: Impl this for the blockState Storage stuff + return null; + } + + @Override + protected boolean isSame(IBlockDetailWrapper iBlockDetail) + { + return ((BlockDetailWrapper)iBlockDetail).state.getBlock().equals(state.getBlock()); + } + +} diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/chunk/ChunkWrapper.java b/common/src/main/java/com/seibel/lod/common/wrappers/chunk/ChunkWrapper.java index cf9920e69..885123a64 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/chunk/ChunkWrapper.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/chunk/ChunkWrapper.java @@ -2,12 +2,12 @@ package com.seibel.lod.common.wrappers.chunk; import com.seibel.lod.core.util.LevelPosUtil; import com.seibel.lod.core.util.LodUtil; -import com.seibel.lod.core.wrapperInterfaces.block.BlockDetail; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper; import com.seibel.lod.common.wrappers.WrapperUtil; import com.seibel.lod.common.wrappers.block.BlockDetailMap; +import com.seibel.lod.common.wrappers.block.BlockDetailWrapper; import com.seibel.lod.common.wrappers.world.BiomeWrapper; import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.LightedWorldGenRegion; @@ -73,9 +73,11 @@ public class ChunkWrapper implements IChunkWrapper } @Override - public BlockDetail getBlockDetail(int x, int y, int z) { - BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z)); - return BlockDetailMap.getBlockDetailWithCompleteTint(blockState, x, y, z, lightSource); + public BlockDetailWrapper getBlockDetail(int x, int y, int z) { + BlockPos pos = new BlockPos(x,y,z); + BlockState blockState = chunk.getBlockState(pos); + BlockDetailWrapper blockDetail = BlockDetailMap.getOrMakeBlockDetailCache(blockState, pos, lightSource); + return blockDetail == BlockDetailWrapper.NULL_BLOCK_DETAIL ? null : blockDetail; } @@ -178,4 +180,8 @@ public class ChunkWrapper implements IChunkWrapper return true; } + public LevelReader getColorResolver() + { + return lightSource; + } } diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java b/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java index 3749c72c4..a6c243e30 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java @@ -306,6 +306,30 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.useExtendedNearClipPlane").value = newUseExtendedNearClipPlane; ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.useExtendedNearClipPlane"); } + + @Override + public double getBrightnessMultiplier() + { + return Config.Client.Graphics.AdvancedGraphics.brightnessMultiplier; + } + @Override + public void setBrightnessMultiplier(double newBrightnessMultiplier) + { + ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.brightnessMultiplier").value = newBrightnessMultiplier; + ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.brightnessMultiplier"); + } + + @Override + public double getSaturationMultiplier() + { + return Config.Client.Graphics.AdvancedGraphics.saturationMultiplier; + } + @Override + public void setSaturationMultiplier(double newSaturationMultiplier) + { + ConfigGui.editSingleOption.getEntry("client.graphics.advancedGraphics.saturationMultiplier").value = newSaturationMultiplier; + ConfigGui.editSingleOption.saveOption("client.graphics.advancedGraphics.saturationMultiplier"); + } } } diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index e120eb8ac..142c859cf 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -429,7 +429,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv } e.pEvent.emptyNano = System.nanoTime(); e.refreshTimeout(); - region = new LightedWorldGenRegion(params.level, lightEngine, e.tParam.structFeat, chunks, ChunkStatus.STRUCTURE_STARTS, rangeEmpty, e.lightMode, generator); + region = new LightedWorldGenRegion(params.level, lightEngine, chunks, ChunkStatus.STRUCTURE_STARTS, rangeEmpty, e.lightMode, generator); adaptor.setRegion(region); e.tParam.makeStructFeat(region); referencedChunks = chunks.subGrid(e.range); diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/mimicObject/LightedWorldGenRegion.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/mimicObject/LightedWorldGenRegion.java index f5b48fc0b..cc78f587e 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/mimicObject/LightedWorldGenRegion.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/mimicObject/LightedWorldGenRegion.java @@ -10,16 +10,24 @@ import com.seibel.lod.core.api.ClientApi; import com.seibel.lod.core.enums.config.LightGenerationMode; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.color.block.BlockTintCache; +import net.minecraft.client.renderer.BiomeColors; import net.minecraft.core.BlockPos; +import net.minecraft.core.Cursor3D; import net.minecraft.core.SectionPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.ColorResolver; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.StructureFeatureManager; +import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -40,21 +48,25 @@ public class LightedWorldGenRegion extends WorldGenRegion { public final int size; private final ChunkPos firstPos; private final List cache; - private final StructureFeatureManager structFeat; Long2ObjectOpenHashMap chunkMap = new Long2ObjectOpenHashMap(); public LightedWorldGenRegion(ServerLevel serverLevel, WorldGenLevelLightEngine lightEngine, - StructureFeatureManager structFeat, List list, ChunkStatus chunkStatus, int i, + List list, ChunkStatus chunkStatus, int i, LightGenerationMode lightMode, EmptyChunkGenerator generator) { super(serverLevel, list, chunkStatus, i); this.lightMode = lightMode; this.firstPos = list.get(0).getPos(); this.generator = generator; - this.structFeat = structFeat; light = lightEngine; writeRadius = i; cache = list; size = Mth.floor(Math.sqrt(list.size())); + + this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> { + object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.GRASS_COLOR_RESOLVER);})); + object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.FOLIAGE_COLOR_RESOLVER);})); + object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache((pos) -> {return calculateBlockTint(pos, BiomeColors.WATER_COLOR_RESOLVER);})); + }); } // Bypass BCLib mixin overrides. @@ -78,12 +90,6 @@ public class LightedWorldGenRegion extends WorldGenRegion { return true; } - @Override - public List> startsForFeature(SectionPos sectionPos, - StructureFeature structureFeature) { - return structFeat.startsForFeature(sectionPos, structureFeature); - } - // Skip updating the related tile entities @Override public boolean setBlock(BlockPos blockPos, BlockState blockState, int i, int j) { @@ -225,4 +231,34 @@ public class LightedWorldGenRegion extends WorldGenRegion { return (getBrightness(LightLayer.SKY, blockPos) >= getMaxLightLevel()); } + + private final Object2ObjectArrayMap tintCaches; + + public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) + { + BlockTintCache blockTintCache = (BlockTintCache) this.tintCaches.get(colorResolver); + return blockTintCache.getColor(blockPos); + } + + public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver) + { + int i = (Minecraft.getInstance()).options.biomeBlendRadius; + if (i == 0) + return colorResolver.getColor((Biome) getBiome(blockPos), blockPos.getX(), blockPos.getZ()); + int j = (i * 2 + 1) * (i * 2 + 1); + int k = 0; + int l = 0; + int m = 0; + Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i); + BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + while (cursor3D.advance()) + { + mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ()); + int n = colorResolver.getColor((Biome) getBiome((BlockPos) mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ()); + k += (n & 0xFF0000) >> 16; + l += (n & 0xFF00) >> 8; + m += n & 0xFF; + } + return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF; + } } \ No newline at end of file diff --git a/core b/core index 510058b7d..bca2b6180 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 510058b7dfa8eb29e0d1de7028e54bea2691e53e +Subproject commit bca2b61800b613b630def131e9c9f85f9736493d