diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/DependencySetup.java b/common/src/main/java/com/seibel/lod/common/wrappers/DependencySetup.java
index 4e9b72ec9..d60c9e589 100644
--- a/common/src/main/java/com/seibel/lod/common/wrappers/DependencySetup.java
+++ b/common/src/main/java/com/seibel/lod/common/wrappers/DependencySetup.java
@@ -1,7 +1,6 @@
package com.seibel.lod.common.wrappers;
import com.seibel.lod.common.LodCommonMain;
-import com.seibel.lod.common.wrappers.block.BlockColorSingletonWrapper;
import com.seibel.lod.common.wrappers.minecraft.MinecraftRenderWrapper;
import com.seibel.lod.common.wrappers.minecraft.MinecraftWrapper;
import com.seibel.lod.core.handlers.IReflectionHandler;
@@ -9,7 +8,6 @@ import com.seibel.lod.core.handlers.ReflectionHandler;
import com.seibel.lod.core.util.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
-import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorSingletonWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
@@ -25,7 +23,6 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
*/
public class DependencySetup {
public static void createInitialBindings() {
- SingletonHandler.bind(IBlockColorSingletonWrapper.class, BlockColorSingletonWrapper.INSTANCE);
if (!LodCommonMain.serverSided) {
SingletonHandler.bind(IMinecraftWrapper.class, MinecraftWrapper.INSTANCE);
SingletonHandler.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockColorSingletonWrapper.java b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockColorSingletonWrapper.java
deleted file mode 100644
index ab1023444..000000000
--- a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockColorSingletonWrapper.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * This file is part of the Distant Horizon mod (formerly the LOD Mod),
- * licensed under the GNU GPL v3 License.
- *
- * Copyright (C) 2020 James Seibel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package com.seibel.lod.common.wrappers.block;
-
-import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorSingletonWrapper;
-import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
-
-import net.minecraft.world.level.block.Blocks;
-
-
-/**
- * Contains methods that would have been static in BlockColorWrapper.
- * Since interfaces can't create/implement static methods we have
- * to split the object up in two.
- *
- * @author James Seibel
- * @version 11-17-2021
- */
-public class BlockColorSingletonWrapper implements IBlockColorSingletonWrapper
-{
- public static final BlockColorSingletonWrapper INSTANCE = new BlockColorSingletonWrapper();
-
- @Override
- public IBlockColorWrapper getWaterColor()
- {
- return BlockColorWrapper.getBlockColorWrapper(Blocks.WATER);
- }
-}
-
diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockColorWrapper.java b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockColorWrapper.java
deleted file mode 100644
index e1d76ab6a..000000000
--- a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockColorWrapper.java
+++ /dev/null
@@ -1,317 +0,0 @@
-package com.seibel.lod.common.wrappers.block;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.Random;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import com.seibel.lod.common.wrappers.minecraft.MinecraftWrapper;
-import com.seibel.lod.core.util.ColorUtil;
-import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper;
-import com.seibel.lod.core.wrapperInterfaces.block.IBlockColorWrapper;
-
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.minecraft.client.renderer.texture.TextureAtlasSprite;
-import net.minecraft.core.Direction;
-import net.minecraft.world.level.block.*;
-import net.minecraft.world.level.block.state.BlockState;
-
-
-/**
- * @author James Seibel
- * @version 11-21-2021
- */
-public class BlockColorWrapper implements IBlockColorWrapper
-{
- //set of block which require tint
- public static final ConcurrentMap blockColorWrapperMap = new ConcurrentHashMap<>();
- // public static final ModelDataMap dataMap = new ModelDataMap.Builder().build();
- public static final AbstractBlockPosWrapper blockPos = new BlockPosWrapper(0, 0, 0);
- public static final Random random = new Random(0);
- //public static BlockColourWrapper WATER_COLOR = getBlockColorWrapper(Blocks.WATER);
- public static final Direction[] directions = new Direction[] { Direction.UP, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH, Direction.DOWN };
-
- private final Block block;
- private int color;
- private boolean isColored;
- private boolean toTint;
- private boolean foliageTint;
- private boolean grassTint;
- private boolean waterTint;
-
-
- /**Constructor only require for the block instance we are wrapping**/
- public BlockColorWrapper(Block block)
- {
- this.block = block;
- this.color = 0;
- this.isColored = true;
- this.toTint = false;
- this.foliageTint = false;
- this.grassTint = false;
- this.waterTint = false;
- setupColorAndTint();
- /*StringBuilder s = new StringBuilder();
- s.append(block + "\n"
- + Integer.toHexString(
- Minecraft.getInstance().getBlockColors().createDefault().getColor(
- block.defaultBlockState(),
- (World) MinecraftWrapper.INSTANCE.getWrappedServerLevel().getLevel(),
- blockPosWrapper.getBlockPos())) + "\n"
- );
- for(Property x : Minecraft.getInstance().getBlockColors().getColoringProperties(block))
- s.append(x.getName() + " " + x.getPossibleValues() + '\n');
- System.out.println(s);*/
- //System.out.println(block + " color " + Integer.toHexString(color) + " to tint " + toTint + " folliageTint " + folliageTint + " grassTint " + grassTint + " waterTint " + waterTint);
- }
-
-
- /**
- * this return a wrapper of the block in input
- * @param block object of the block to wrap
- */
- public static IBlockColorWrapper getBlockColorWrapper(Block block)
- {
- //first we check if the block has already been wrapped
- BlockColorWrapper colorWrapper = blockColorWrapperMap.get(block);
- if (colorWrapper != null)
- return colorWrapper;
-
- //if it hasn't been created yet, we create it and save it in the map
- colorWrapper = new BlockColorWrapper(block);
- BlockColorWrapper colorWrapperCAS = blockColorWrapperMap.putIfAbsent(block, colorWrapper);
- //we return the newly created wrapper
- return colorWrapperCAS==null ? colorWrapper : colorWrapperCAS;
- }
-
- /**
- * Generate the color of the given block from its texture
- * and store it for later use.
- */
- private void setupColorAndTint()
- {
- BlockState blockState = block.defaultBlockState();
- //BlockPosWrapper blockPosWrapper = new BlockPosWrapper();
- MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
- TextureAtlasSprite texture;
- List quads = null;
-
- //boolean isTinted = false;
- //int listSize = 0;
-
- // first step is to check if this block has a tinted face
- //for (Direction direction : directions)
- //{
- // quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random);
- // listSize = Math.max(listSize, quads.size());
- // for (BakedQuad bakedQuad : quads)
- // {
- // isTinted |= bakedQuad.isTinted();
- // }
- //}
-
- //if it contains a tinted face then we store this block in the toTint set
- //if (isTinted)
- // this.toTint = true;
-
- //now we get the first non-empty face
- for (Direction direction : directions)
- {
- quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random);
- if (!quads.isEmpty() && !(block instanceof RotatedPillarBlock && direction == Direction.UP))
- break;
- }
-
- //the quads list is not empty we extract the first one
- if (!quads.isEmpty())
- {
- isColored = true;
- texture = quads.get(0).getSprite();
- }
- else
- {
- isColored = true;
- texture = mc.getModelManager().getBlockModelShaper().getParticleIcon(block.defaultBlockState());
- }
-
- int count = 0;
- int alpha = 0;
- int red = 0;
- int green = 0;
- int blue = 0;
- int numberOfGreyPixel = 0;
- int tempColor;
- int colorMultiplier;
-
- // generate the block's color
-// for (int frameIndex = 0; frameIndex < texture.getFrameCount(); frameIndex++)
- boolean lookForTint = grassInstance() || leavesInstance();
-
- int frameIndex = 0; // TODO
- {
- // 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++)
- {
- tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, frameIndex, u, v);
-
- if (ColorUtil.getAlpha(TextureAtlasSpriteWrapper.getPixelRGBA(texture, frameIndex, u, v)) == 0)
- continue;
-
- if (lookForTint)
- {
- // determine if this pixel is gray
- int colorMax = Math.max(Math.max(ColorUtil.getBlue(tempColor), ColorUtil.getGreen(tempColor)), ColorUtil.getRed(tempColor));
- int colorMin = 16 + Math.min(Math.min(ColorUtil.getBlue(tempColor), ColorUtil.getGreen(tempColor)), ColorUtil.getRed(tempColor));
- boolean isGray = colorMax < colorMin;
- if (isGray)
- numberOfGreyPixel++;
- }
-
-
- // for flowers, weight their non-green color higher
- if (block instanceof FlowerBlock && (!(ColorUtil.getGreen(tempColor) > (ColorUtil.getBlue(tempColor) + 30)) || !(ColorUtil.getGreen(tempColor) > (ColorUtil.getRed(tempColor) + 30))))
- colorMultiplier = 5;
- else
- colorMultiplier = 1;
-
-
- // add to the running averages
- count += colorMultiplier;
- alpha += ColorUtil.getAlpha(tempColor) * ColorUtil.getAlpha(tempColor) * colorMultiplier;
- red += ColorUtil.getBlue(tempColor) * ColorUtil.getBlue(tempColor) * colorMultiplier;
- green += ColorUtil.getGreen(tempColor) * ColorUtil.getGreen(tempColor) * colorMultiplier;
- blue += ColorUtil.getRed(tempColor) * ColorUtil.getRed(tempColor) * colorMultiplier;
- }
- }
- }
-
-
- if (count == 0)
- // this block is entirely transparent
- tempColor = 0;
- else
- {
- // determine the average color
- tempColor = ColorUtil.rgbToInt(
- (int) Math.sqrt(alpha / count),
- (int) Math.sqrt(red / count),
- (int) Math.sqrt(green / count),
- (int) Math.sqrt(blue / count));
- }
-
- // determine if this block should use the biome color tint
- if ((lookForTint && (float) numberOfGreyPixel / count > 0.75f) || waterInstance())
- this.toTint = true;
-
- // we check which kind of tint we need to apply
- this.grassTint = grassInstance() && toTint;
-
- this.foliageTint = leavesInstance() && toTint;
-
- this.waterTint = waterInstance();
-
- //hardcoded leaves
- if (block == Blocks.SPRUCE_LEAVES)
- color = ColorUtil.multiplyRGBcolors(tempColor, 0xFF619961);
- else if (block == Blocks.BIRCH_LEAVES)
- color = ColorUtil.multiplyRGBcolors(tempColor, 0xFF80A755);
- else
- color = tempColor;
- }
-
- /** determine if the given block should use the biome's grass color */
- private boolean grassInstance()
- {
- return block instanceof GrassBlock
- || block instanceof BushBlock
-// || block instanceof IGrowable
-// || block instanceof AbstractPlantBlock
-// || block instanceof AbstractTopPlantBlock
- || block instanceof TallGrassBlock;
- }
-
- /** determine if the given block should use the biome's foliage color */
- private boolean leavesInstance()
- {
- return (block instanceof LeavesBlock && block != Blocks.SPRUCE_LEAVES && block != Blocks.BIRCH_LEAVES/* && block != Blocks.AZALEA_LEAVES && block != Blocks.FLOWERING_AZALEA_LEAVES*/)
- || block == Blocks.VINE
- || block == Blocks.SUGAR_CANE;
- }
-
- /** determine if the given block should use the biome's foliage color */
- private boolean waterInstance()
- {
- return block == Blocks.WATER;
- }
-
- @Override
- public String getName(){
- return block.getName().toString();
- }
-
-//--------------//
-//Colors getters//
-//--------------//
-
- @Override
- public boolean hasColor()
- {
- return isColored;
- }
-
- @Override
- public int getColor()
- {
- return color;
- }
-
-//------------//
-//Tint getters//
-//------------//
-
-
- @Override
- public boolean hasTint()
- {
- return toTint;
- }
-
- @Override
- public boolean hasGrassTint()
- {
- return grassTint;
- }
-
- @Override
- public boolean hasFolliageTint()
- {
- return foliageTint;
- }
-
- @Override
- public boolean hasWaterTint()
- {
- return waterTint;
- }
-
-
-
-
- @Override public boolean equals(Object o)
- {
- if (this == o)
- return true;
- if (!(o instanceof BlockColorWrapper))
- return false;
- BlockColorWrapper that = (BlockColorWrapper) o;
- return Objects.equals(block, that.block);
- }
-
- @Override public int hashCode()
- {
- return Objects.hash(block);
- }
-}
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
new file mode 100644
index 000000000..282e1870b
--- /dev/null
+++ b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailMap.java
@@ -0,0 +1,249 @@
+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.ClientApi;
+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.BlockAndTintGetter;
+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.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;
+
+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) {
+
+ int count = 0;
+ int alpha = 0;
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+ int tempColor;
+ int colorMultiplier;
+
+ {
+ // 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++)
+ {
+ tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
+
+ if (ColorUtil.getAlpha(TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v)) == 0)
+ continue;
+
+ // for flowers, weight their non-green color higher
+ if (useFlowerScaling && (
+ !(ColorUtil.getGreen(tempColor) > (ColorUtil.getBlue(tempColor) + 30)) ||
+ !(ColorUtil.getGreen(tempColor) > (ColorUtil.getRed(tempColor) + 30))
+ ))
+ colorMultiplier = FLOWER_COLOR_SCALE;
+ else
+ colorMultiplier = 1;
+
+ // add to the running averages
+ count += colorMultiplier;
+ alpha += ColorUtil.getAlpha(tempColor) * ColorUtil.getAlpha(tempColor) * colorMultiplier;
+ red += ColorUtil.getBlue(tempColor) * ColorUtil.getBlue(tempColor) * colorMultiplier;
+ green += ColorUtil.getGreen(tempColor) * ColorUtil.getGreen(tempColor) * colorMultiplier;
+ blue += ColorUtil.getRed(tempColor) * ColorUtil.getRed(tempColor) * colorMultiplier;
+ }
+ }
+ }
+
+ if (count == 0)
+ // this block is entirely transparent
+ tempColor = 0;
+ else
+ {
+ // determine the average color
+ tempColor = ColorUtil.rgbToInt(
+ (int) Math.sqrt(alpha / count),
+ (int) Math.sqrt(red / count),
+ (int) Math.sqrt(green / count),
+ (int) Math.sqrt(blue / count));
+ }
+ return tempColor;
+ }
+
+
+ static class BlockDetailCache {
+ static BlockDetailCache NULL_BLOCK_DETAIL = new BlockDetailCache();
+
+ private static final Block[] BLOCK_TO_AVOID = {Blocks.AIR, Blocks.CAVE_AIR, Blocks.BARRIER};
+
+ private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN};
+
+
+ BlockDetail blockDetail;
+ 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, BlockAndTintGetter 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, BlockAndTintGetter 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, BlockAndTintGetter 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);
+ ClientApi.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);
+ ClientApi.LOGGER.info(bs.toString()+" = ["+result+"]");
+ return result;
+ }
+ }
+
+ BlockDetailCache(boolean isFullBlock, boolean noCol, boolean nonFull, BakedQuad quad, boolean useFlowerScaling) {
+ requireResolving = quad.isTinted();
+ requireShade = quad.isShade();
+ tintIndex = quad.getTintIndex();
+ scaleFlowerColor = useFlowerScaling;
+ blockDetail = new BlockDetail(calculateColorFromTexture(quad.getSprite(), useFlowerScaling), isFullBlock, noCol, nonFull);
+ }
+
+ 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), true, false, false);
+ }
+
+ private BlockDetailCache()
+ {
+ //DUMMY CREATOR
+ }
+
+ BlockDetail getResolvedBlockDetail(BlockState bs, int x, int y, int z, BlockAndTintGetter getter) {
+ if (!requireResolving) return blockDetail;
+ BlockColors bc = Minecraft.getInstance().getBlockColors();
+ if (!bs.getFluidState().isEmpty()) bs = bs.getFluidState().createLegacyBlock();
+ int tintColor = bc.getColor(bs, getter, new BlockPos(x, y, z), tintIndex);
+ if (tintColor == -1) return blockDetail;
+ return new BlockDetail(ColorUtil.multiplyRGBcolors(blockDetail.color, tintColor),
+ blockDetail.isFullBlock, blockDetail.hasNoCollision, blockDetail.hasOnlyNonFullFace);
+ }
+
+ // 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;
+ BlockColors bc = Minecraft.getInstance().getBlockColors();
+ if (!bs.getFluidState().isEmpty()) bs = bs.getFluidState().createLegacyBlock();
+ int tintColor = bc.getColor(bs, null, null, tintIndex);
+ if (tintColor == -1) return blockDetail;
+ return new BlockDetail(ColorUtil.multiplyRGBcolors(blockDetail.color, tintColor),
+ blockDetail.isFullBlock, blockDetail.hasNoCollision, blockDetail.hasOnlyNonFullFace);
+ }
+
+ @Override
+ public String toString() {
+ return "[BlockDetail: "+blockDetail+", RequireResolving: "+requireResolving+", requireShade: "+requireShade+", scaleFlowerColor: "+scaleFlowerColor+"]";
+ }
+
+ }
+
+
+
+ private static ConcurrentHashMap map = new ConcurrentHashMap();
+
+ private BlockDetailMap() {}
+
+ private static BlockDetailCache getOrMakeBlockDetailCache(BlockState bs, BlockPos pos, BlockAndTintGetter getter) {
+ BlockDetailCache cache = map.get(bs);
+ if (cache != null) return cache;
+ if (bs.getFluidState().isEmpty()) {
+ cache = BlockDetailCache.make(bs, pos, getter);
+ } else {
+ cache = BlockDetailCache.make(bs.getFluidState().createLegacyBlock(), pos, getter);
+ }
+ BlockDetailCache 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, BlockAndTintGetter 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/BlockShapeWrapper.java b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockShapeWrapper.java
deleted file mode 100644
index b25991ff4..000000000
--- a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockShapeWrapper.java
+++ /dev/null
@@ -1,157 +0,0 @@
-
-package com.seibel.lod.common.wrappers.block;
-
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import com.seibel.lod.core.wrapperInterfaces.block.IBlockShapeWrapper;
-import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
-import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
-
-import net.minecraft.core.BlockPos;
-import net.minecraft.world.level.block.Block;
-import net.minecraft.world.level.block.Blocks;
-import net.minecraft.world.level.chunk.ChunkAccess;
-import net.minecraft.world.phys.AABB;
-import net.minecraft.world.phys.shapes.VoxelShape;
-
-
-/**
- * @author James Seibel
- * @version 11-21-2021
- */
-public class BlockShapeWrapper implements IBlockShapeWrapper
-{
- //set of block which require tint
- public static final ConcurrentMap blockShapeWrapperMap = new ConcurrentHashMap<>();
- public static BlockShapeWrapper WATER_SHAPE = new BlockShapeWrapper();
-
- private final Block block;
- private final boolean toAvoid;
- private boolean nonFull;
- private boolean noCollision;
-
- /**Constructor only require for the block instance we are wrapping**/
- public BlockShapeWrapper(Block block, IChunkWrapper chunkWrapper, int x, int y, int z)
- {
- this.block = block;
- this.nonFull = false;
- this.noCollision = false;
- this.toAvoid = ofBlockToAvoid();
- setupShapes(chunkWrapper, x, y, z);
- //System.out.println(block + " non full " + nonFull + " no collision " + noCollision + " to avoid " + toAvoid);
- }
-
- private BlockShapeWrapper()
- {
- this.block = Blocks.WATER;
- this.nonFull = false;
- this.noCollision = false;
- this.toAvoid = false;
- }
-
- /**
- * this return a wrapper of the block in input
- * @param block Block object to wrap
- */
- static public BlockShapeWrapper getBlockShapeWrapper(Block block, ChunkWrapper chunkWrapper, int x, int y, int z)
- {
- //first we check if the block has already been wrapped
- BlockShapeWrapper blockWrapper = blockShapeWrapperMap.get(block);
- if (blockWrapper != null)
- return blockWrapper;
-
- //if it hasn't been created yet, we create it and save it in the map
- blockWrapper = new BlockShapeWrapper(block, chunkWrapper, x, y, z);
- BlockShapeWrapper blockWrapperCAS = blockShapeWrapperMap.putIfAbsent(block, blockWrapper);
- //we return the newly created wrapper
- return blockWrapperCAS==null ? blockWrapper : blockWrapperCAS;
- }
-
- private void setupShapes(IChunkWrapper chunkWrapper, int x, int y, int z)
- {
- ChunkAccess chunk = ((ChunkWrapper) chunkWrapper).getChunk();
- BlockPos blockPos = new BlockPos(x, y, z);
- boolean noCollisionSetted = false;
- boolean nonFullSetted = false;
- if (!block.defaultBlockState().getFluidState().isEmpty())// || block instanceof SixWayBlock)
- {
- noCollisionSetted = true;
- nonFullSetted = true;
- noCollision = false;
- nonFull = false;
- }
- if (!nonFullSetted)
- {
- VoxelShape voxelShape = block.defaultBlockState().getShape(chunk, blockPos);
-
- if (!voxelShape.isEmpty())
- {
- AABB bbox = voxelShape.bounds();
- double xWidth = (bbox.maxX - bbox.minX);
- double yWidth = (bbox.maxY - bbox.minY);
- double zWidth = (bbox.maxZ - bbox.minZ);
- nonFull = xWidth < 1 && zWidth < 1 && yWidth < 1;
- }
- else
- {
- nonFull = false;
- }
- }
-
- if (!noCollisionSetted)
- {
- VoxelShape collisionShape = block.defaultBlockState().getCollisionShape(chunk, blockPos);
- noCollision = collisionShape.isEmpty();
- }
- }
-
- @Override
- public boolean ofBlockToAvoid()
- {
- return block.equals(Blocks.AIR)
- || block.equals(Blocks.CAVE_AIR)
- || block.equals(Blocks.BARRIER);
- }
-//-----------------//
-//Avoidance getters//
-//-----------------//
-
-
- @Override
- public boolean isNonFull()
- {
- return nonFull;
- }
-
- @Override
- public boolean hasNoCollision()
- {
- return noCollision;
- }
-
- @Override
- public boolean isToAvoid()
- {
- return toAvoid;
- }
-
-
-
-
- @Override public boolean equals(Object o)
- {
- if (this == o)
- return true;
- if (!(o instanceof BlockShapeWrapper))
- return false;
- BlockShapeWrapper that = (BlockShapeWrapper) o;
- return Objects.equals(block, that.block);
- }
-
- @Override public int hashCode()
- {
- return Objects.hash(block);
- }
-}
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 8941cfe58..ca80de825 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,29 +2,27 @@ 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.IBlockColorWrapper;
-import com.seibel.lod.core.wrapperInterfaces.block.IBlockShapeWrapper;
+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.BlockColorWrapper;
-import com.seibel.lod.common.wrappers.block.BlockShapeWrapper;
+import com.seibel.lod.common.wrappers.block.BlockDetailMap;
import com.seibel.lod.common.wrappers.world.BiomeWrapper;
+import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.LightedWorldGenRegion;
import net.minecraft.core.BlockPos;
import net.minecraft.core.QuartPos;
import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LightLayer;
-import net.minecraft.world.level.block.AirBlock;
-import net.minecraft.world.level.block.Block;
-import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.LiquidBlockContainer;
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
-import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.levelgen.Heightmap;
/**
@@ -35,7 +33,7 @@ import net.minecraft.world.level.levelgen.Heightmap;
public class ChunkWrapper implements IChunkWrapper
{
private final ChunkAccess chunk;
- private final BlockAndTintGetter lightSource;
+ private final LevelReader lightSource;
@Override
public int getHeight(){
@@ -65,30 +63,14 @@ public class ChunkWrapper implements IChunkWrapper
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
}
-
+
@Override
- public IBlockColorWrapper getBlockColorWrapper(int x, int y, int z)
- {
+ public BlockDetail getBlockDetail(int x, int y, int z) {
BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z));
- Block block = blockState.getBlock();
- return BlockColorWrapper.getBlockColorWrapper(block);
+ return BlockDetailMap.getBlockDetailWithCompleteTint(blockState, x, y, z, lightSource);
}
-
- @Override
- public IBlockShapeWrapper getBlockShapeWrapper(int x, int y, int z)
- {
- BlockState blockState = chunk.getBlockState(new BlockPos(x,y,z));
- Block block = blockState.getBlock();
- return BlockShapeWrapper.getBlockShapeWrapper(block, this, x, y, z);
- }
-
- @Deprecated
- public ChunkWrapper(ChunkAccess chunk)
- {
- this.chunk = chunk;
- this.lightSource = null;
- }
- public ChunkWrapper(ChunkAccess chunk, BlockAndTintGetter lightSource)
+
+ public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource)
{
this.chunk = chunk;
this.lightSource = lightSource;
@@ -180,5 +162,17 @@ public class ChunkWrapper implements IChunkWrapper
if (lightSource == null) return -1;
return lightSource.getBrightness(LightLayer.SKY, new BlockPos(x,y,z));
}
+
+ @Override
+ public boolean doesNearbyChunksExist() {
+ if (lightSource instanceof LightedWorldGenRegion) return true;
+ for (int dx = -1; dx <= 1; dx++) {
+ for (int dz = -1; dz <= 1; dz++) {
+ if (dx==0 && dz==0) continue;
+ if (lightSource.getChunk(dx+getChunkPosX(), dz+getChunkPosZ(), ChunkStatus.BIOMES, false) == null) return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/core b/core
index 0edca2402..4708da8e8 160000
--- a/core
+++ b/core
@@ -1 +1 @@
-Subproject commit 0edca2402d8ca75dd0dcbe2923a5d2133d3f48ae
+Subproject commit 4708da8e8ff5c7c695b7b8691335db85dae054d8