Implemented the wrappers in the lodBuilder
This commit is contained in:
@@ -19,9 +19,6 @@
|
||||
|
||||
package com.seibel.lod.builders.lodBuilding;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -30,11 +27,9 @@ import java.util.concurrent.Executors;
|
||||
import com.seibel.lod.config.LodConfig;
|
||||
import com.seibel.lod.enums.DistanceGenerationMode;
|
||||
import com.seibel.lod.enums.HorizontalResolution;
|
||||
import com.seibel.lod.enums.VerticalQuality;
|
||||
import com.seibel.lod.objects.LodDimension;
|
||||
import com.seibel.lod.objects.LodRegion;
|
||||
import com.seibel.lod.objects.LodWorld;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
import com.seibel.lod.util.ColorUtil;
|
||||
import com.seibel.lod.util.DataPointUtil;
|
||||
import com.seibel.lod.util.DetailDistanceUtil;
|
||||
@@ -42,47 +37,23 @@ import com.seibel.lod.util.LevelPosUtil;
|
||||
import com.seibel.lod.util.LodThreadFactory;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.util.ThreadMapUtil;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.Block.BlockWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
|
||||
import net.minecraft.block.AbstractPlantBlock;
|
||||
import net.minecraft.block.AbstractTopPlantBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import com.seibel.lod.wrappers.World.BiomeWrapper;
|
||||
import com.seibel.lod.wrappers.World.WorldWrapper;
|
||||
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.BushBlock;
|
||||
import net.minecraft.block.FlowerBlock;
|
||||
import net.minecraft.block.GrassBlock;
|
||||
import net.minecraft.block.IGrowable;
|
||||
import net.minecraft.block.ILiquidContainer;
|
||||
import net.minecraft.block.IWaterLoggable;
|
||||
import net.minecraft.block.LeavesBlock;
|
||||
import net.minecraft.block.SixWayBlock;
|
||||
import net.minecraft.block.TallGrassBlock;
|
||||
import net.minecraft.block.material.MaterialColor;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.data.BlockModelProvider;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.LightType;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeColors;
|
||||
import net.minecraft.world.chunk.ChunkSection;
|
||||
import net.minecraft.world.chunk.IChunk;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.client.model.data.ModelDataMap;
|
||||
|
||||
/**
|
||||
* This object is in charge of creating Lod related objects.
|
||||
*
|
||||
*
|
||||
* @author Cola
|
||||
* @author Leonardo Amato
|
||||
* @author James Seibel
|
||||
@@ -94,18 +65,6 @@ public class LodBuilder
|
||||
|
||||
private final ExecutorService lodGenThreadPool = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName()));
|
||||
|
||||
public static final Direction[] directions = new Direction[] { Direction.UP, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH, Direction.DOWN };
|
||||
public static final int CHUNK_DATA_WIDTH = LodUtil.CHUNK_WIDTH;
|
||||
public static final int CHUNK_SECTION_HEIGHT = CHUNK_DATA_WIDTH;
|
||||
public static final ConcurrentMap<Block, Integer> colorMap = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<Block, Integer> tintColor = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<Block, Boolean> toTint = new ConcurrentHashMap<>();
|
||||
|
||||
public static final ConcurrentMap<Block, Boolean> notFullBlock = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<Block, Boolean> smallBlock = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public static final ModelDataMap dataMap = new ModelDataMap.Builder().build();
|
||||
|
||||
/** If no blocks are found in the area in determineBottomPointForArea return this */
|
||||
public static final short DEFAULT_DEPTH = 0;
|
||||
@@ -131,12 +90,12 @@ public class LodBuilder
|
||||
|
||||
}
|
||||
|
||||
public void generateLodNodeAsync(IChunk chunk, LodWorld lodWorld, IWorld world)
|
||||
public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, IWorld world)
|
||||
{
|
||||
generateLodNodeAsync(chunk, lodWorld, world, DistanceGenerationMode.SERVER);
|
||||
}
|
||||
|
||||
public void generateLodNodeAsync(IChunk chunk, LodWorld lodWorld, IWorld world, DistanceGenerationMode generationMode)
|
||||
public void generateLodNodeAsync(ChunkWrapper chunk, LodWorld lodWorld, IWorld world, DistanceGenerationMode generationMode)
|
||||
{
|
||||
if (lodWorld == null || lodWorld.getIsWorldNotLoaded())
|
||||
return;
|
||||
@@ -191,7 +150,7 @@ public class LodBuilder
|
||||
* Creates a LodNode for a chunk in the given world.
|
||||
* @throws IllegalArgumentException thrown if either the chunk or world is null.
|
||||
*/
|
||||
public void generateLodNodeFromChunk(LodDimension lodDim, IChunk chunk) throws IllegalArgumentException
|
||||
public void generateLodNodeFromChunk(LodDimension lodDim, ChunkWrapper chunk) throws IllegalArgumentException
|
||||
{
|
||||
generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig());
|
||||
}
|
||||
@@ -200,7 +159,7 @@ public class LodBuilder
|
||||
* Creates a LodNode for a chunk in the given world.
|
||||
* @throws IllegalArgumentException thrown if either the chunk or world is null.
|
||||
*/
|
||||
public void generateLodNodeFromChunk(LodDimension lodDim, IChunk chunk, LodBuilderConfig config)
|
||||
public void generateLodNodeFromChunk(LodDimension lodDim, ChunkWrapper chunk, LodBuilderConfig config)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if (chunk == null)
|
||||
@@ -237,23 +196,23 @@ public class LodBuilder
|
||||
endZ = detail.endZ[i];
|
||||
|
||||
long[] data;
|
||||
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ, endX, endZ);
|
||||
long[] dataToMergeVertical = createVerticalDataToMerge(detail, chunk, config, startX, startZ);
|
||||
data = DataPointUtil.mergeMultiData(dataToMergeVertical, DataPointUtil.worldHeight / 2 + 1, DetailDistanceUtil.getMaxVerticalData(detailLevel));
|
||||
|
||||
|
||||
//lodDim.clear(detailLevel, posX, posZ);
|
||||
if (data != null && data.length != 0)
|
||||
{
|
||||
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().x * 16 + startX, detail.detailLevel);
|
||||
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().z * 16 + startZ, detail.detailLevel);
|
||||
posX = LevelPosUtil.convert((byte) 0, chunk.getPos().getX() * 16 + startX, detail.detailLevel);
|
||||
posZ = LevelPosUtil.convert((byte) 0, chunk.getPos().getZ() * 16 + startZ, detail.detailLevel);
|
||||
lodDim.addVerticalData(detailLevel, posX, posZ, data, false);
|
||||
}
|
||||
}
|
||||
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().x, chunk.getPos().z);
|
||||
lodDim.updateData(LodUtil.CHUNK_DETAIL_LEVEL, chunk.getPos().getX(), chunk.getPos().getZ());
|
||||
}
|
||||
|
||||
/** creates a vertical DataPoint */
|
||||
private long[] createVerticalDataToMerge(HorizontalResolution detail, IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ)
|
||||
private long[] createVerticalDataToMerge(HorizontalResolution detail, ChunkWrapper chunk, LodBuilderConfig config, int startX, int startZ)
|
||||
{
|
||||
// equivalent to 2^detailLevel
|
||||
int size = 1 << detail.detailLevel;
|
||||
@@ -262,7 +221,7 @@ public class LodBuilder
|
||||
|
||||
int verticalData = DataPointUtil.worldHeight / 2 + 1;
|
||||
|
||||
ChunkPos chunkPos = chunk.getPos();
|
||||
ChunkPosWrapper chunkPos = chunk.getPos();
|
||||
int height;
|
||||
int depth;
|
||||
int color;
|
||||
@@ -279,7 +238,7 @@ public class LodBuilder
|
||||
boolean hasCeiling = mc.getClientWorld().dimensionType().hasCeiling();
|
||||
boolean hasSkyLight = mc.getClientWorld().dimensionType().hasSkyLight();
|
||||
boolean isDefault;
|
||||
BlockPos.Mutable blockPos = new BlockPos.Mutable(0, 0, 0);
|
||||
BlockPosWrapper blockPos = new BlockPosWrapper();
|
||||
int index;
|
||||
|
||||
for (index = 0; index < size * size; index++)
|
||||
@@ -295,7 +254,7 @@ public class LodBuilder
|
||||
boolean topBlock = true;
|
||||
while (yAbs > 0)
|
||||
{
|
||||
height = determineHeightPointFrom(chunk, config, xRel, zRel, yAbs, blockPos);
|
||||
height = determineHeightPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
|
||||
|
||||
// If the lod is at the default height, it must be void data
|
||||
if (height == DEFAULT_HEIGHT)
|
||||
@@ -307,13 +266,13 @@ public class LodBuilder
|
||||
|
||||
yAbs = height - 1;
|
||||
// We search light on above air block
|
||||
depth = determineBottomPointFrom(chunk, config, xRel, zRel, yAbs, blockPos);
|
||||
depth = determineBottomPointFrom(chunk, config, xRel, yAbs, zRel, blockPos);
|
||||
if (hasCeiling && topBlock)
|
||||
{
|
||||
yAbs = depth;
|
||||
blockPos.set(xAbs, yAbs, zAbs);
|
||||
light = getLightValue(chunk, blockPos, hasCeiling, hasSkyLight, topBlock);
|
||||
color = generateLodColor(chunk, config, xRel, yAbs, zRel, blockPos);
|
||||
color = generateLodColor(chunk, config, xAbs, yAbs, zAbs, blockPos);
|
||||
blockPos.set(xAbs, yAbs - 1, zAbs);
|
||||
}
|
||||
else
|
||||
@@ -340,67 +299,39 @@ public class LodBuilder
|
||||
* Find the lowest valid point from the bottom.
|
||||
* Used when creating a vertical LOD.
|
||||
*/
|
||||
private short determineBottomPointFrom(IChunk chunk, LodBuilderConfig config, int xRel, int zRel, int yAbs, BlockPos.Mutable blockPos)
|
||||
private short determineBottomPointFrom(ChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs, BlockPosWrapper blockPos)
|
||||
{
|
||||
short depth = DEFAULT_DEPTH;
|
||||
/*if (config.useHeightmap)
|
||||
|
||||
for (int y = yAbs; y >= 0; y--)
|
||||
{
|
||||
// when using the generated heightmap there is no data about the lowest point
|
||||
depth = 0; //DEFAULT_DEPTH == 0
|
||||
}
|
||||
else
|
||||
{*/
|
||||
boolean voidData = true;
|
||||
ChunkSection[] chunkSections = chunk.getSections();
|
||||
for (int sectionIndex = chunkSections.length - 1; sectionIndex >= 0; sectionIndex--)
|
||||
{
|
||||
for (int yRel = CHUNK_DATA_WIDTH - 1; yRel >= 0; yRel--)
|
||||
blockPos.set(xAbs, y, zAbs);
|
||||
if (!isLayerValidLodPoint(chunk, blockPos))
|
||||
{
|
||||
if (sectionIndex * CHUNK_DATA_WIDTH + yRel > yAbs)
|
||||
continue;
|
||||
|
||||
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel);
|
||||
if (!isLayerValidLodPoint(chunk, blockPos))
|
||||
{
|
||||
depth = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel + 1);
|
||||
voidData = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!voidData)
|
||||
depth = (short) (y + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//}
|
||||
return depth;
|
||||
}
|
||||
|
||||
/** Find the highest valid point from the Top */
|
||||
private short determineHeightPointFrom(IChunk chunk, LodBuilderConfig config, int xRel, int zRel, int yAbs, BlockPos.Mutable blockPos)
|
||||
private short determineHeightPointFrom(ChunkWrapper chunk, LodBuilderConfig config, int xAbs, int yAbs, int zAbs, BlockPosWrapper blockPos)
|
||||
{
|
||||
short height = DEFAULT_HEIGHT;
|
||||
if (config.useHeightmap)
|
||||
height = (short) chunk.getOrCreateHeightmapUnprimed(LodUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
|
||||
height = (short) chunk.getHeightMapValue(xAbs, zAbs);
|
||||
else
|
||||
{
|
||||
boolean voidData = true;
|
||||
ChunkSection[] chunkSections = chunk.getSections();
|
||||
for (int sectionIndex = chunkSections.length - 1; sectionIndex >= 0; sectionIndex--)
|
||||
for (int y = yAbs; y >= 0; y--)
|
||||
{
|
||||
for (int yRel = CHUNK_DATA_WIDTH - 1; yRel >= 0; yRel--)
|
||||
blockPos.set(xAbs, y, zAbs);
|
||||
blockPos.set(xAbs, y, zAbs);
|
||||
if (isLayerValidLodPoint(chunk, blockPos))
|
||||
{
|
||||
if (sectionIndex * CHUNK_DATA_WIDTH + yRel > yAbs)
|
||||
continue;
|
||||
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel);
|
||||
if (isLayerValidLodPoint(chunk, blockPos))
|
||||
{
|
||||
height = (short) (sectionIndex * CHUNK_DATA_WIDTH + yRel + 1);
|
||||
voidData = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!voidData)
|
||||
height = (short) (y + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return height;
|
||||
@@ -416,26 +347,19 @@ public class LodBuilder
|
||||
* Generate the color for the given chunk using biome water color, foliage
|
||||
* color, and grass color.
|
||||
*/
|
||||
private int generateLodColor(IChunk chunk, LodBuilderConfig config, int xRel, int yAbs, int zRel, BlockPos.Mutable blockPos)
|
||||
private int generateLodColor(ChunkWrapper chunk, LodBuilderConfig config, int xRel, int yAbs, int zRel, BlockPosWrapper blockPos)
|
||||
{
|
||||
ChunkSection[] chunkSections = chunk.getSections();
|
||||
int colorInt = 0;
|
||||
if (config.useBiomeColors)
|
||||
{
|
||||
// I have no idea why I need to bit shift to the right, but
|
||||
// if I don't the biomes don't show up correctly.
|
||||
Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, yAbs >> 2, zRel >> 2);
|
||||
colorInt = getColorForBiome(xRel, zRel, biome);
|
||||
colorInt = chunk.getBiome(xRel, yAbs, zRel).getColorForBiome(xRel, zRel);
|
||||
}
|
||||
else
|
||||
{
|
||||
int sectionIndex = Math.floorDiv(yAbs, CHUNK_SECTION_HEIGHT);
|
||||
int yRel = Math.floorMod(yAbs, CHUNK_SECTION_HEIGHT);
|
||||
if (chunkSections[sectionIndex] != null)
|
||||
{
|
||||
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel, chunk.getPos().getMinBlockZ() + zRel);
|
||||
colorInt = getColorForBlock(chunk, blockPos);
|
||||
}
|
||||
blockPos.set(chunk.getPos().getMinBlockX() + xRel, yAbs, chunk.getPos().getMinBlockZ() + zRel);
|
||||
colorInt = getColorForBlock(chunk, blockPos);
|
||||
|
||||
// if we are skipping non-full and non-solid blocks that means we ignore
|
||||
// snow, flowers, etc. Get the above block so we can still get the color
|
||||
@@ -443,7 +367,7 @@ public class LodBuilder
|
||||
int aboveColorInt = 0;
|
||||
if (LodConfig.CLIENT.worldGenerator.blockToAvoid.get().nonFull || LodConfig.CLIENT.worldGenerator.blockToAvoid.get().noCollision)
|
||||
{
|
||||
blockPos.set(chunk.getPos().getMinBlockX() + xRel, sectionIndex * CHUNK_DATA_WIDTH + yRel + 1, chunk.getPos().getMinBlockZ() + zRel);
|
||||
blockPos.set(chunk.getPos().getMinBlockX() + xRel, yAbs + 1, chunk.getPos().getMinBlockZ() + zRel);
|
||||
aboveColorInt = getColorForBlock(chunk, blockPos);
|
||||
}
|
||||
|
||||
@@ -461,21 +385,16 @@ public class LodBuilder
|
||||
}
|
||||
|
||||
/** Gets the light value for the given block position */
|
||||
private int getLightValue(IChunk chunk, BlockPos.Mutable blockPos, boolean hasCeiling, boolean hasSkyLight, boolean topBlock)
|
||||
private int getLightValue(ChunkWrapper chunk, BlockPosWrapper blockPos, boolean hasCeiling, boolean hasSkyLight, boolean topBlock)
|
||||
{
|
||||
int skyLight = 0;
|
||||
int blockLight;
|
||||
// 1 means the lighting is a guess
|
||||
int isDefault = 0;
|
||||
|
||||
WorldWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerWorld();
|
||||
|
||||
ClientWorld clientWorld = mc.getClientWorld();
|
||||
if (clientWorld == null)
|
||||
return 0;
|
||||
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(clientWorld.dimensionType());
|
||||
|
||||
|
||||
int blockBrightness = chunk.getLightEmission(blockPos);
|
||||
int blockBrightness = chunk.getEmittedBrightness(blockPos);
|
||||
// get the air block above or below this block
|
||||
if (hasCeiling && topBlock)
|
||||
blockPos.set(blockPos.getX(), blockPos.getY() - 1, blockPos.getZ());
|
||||
@@ -484,14 +403,14 @@ public class LodBuilder
|
||||
|
||||
|
||||
|
||||
if (serverWorld != null)
|
||||
if (world.isEmpty())
|
||||
{
|
||||
// server world sky light (always accurate)
|
||||
blockLight = serverWorld.getBrightness(LightType.BLOCK, blockPos);
|
||||
if(topBlock && !hasCeiling && hasSkyLight)
|
||||
blockLight = world.getBlockLight(blockPos);
|
||||
if (topBlock && !hasCeiling && hasSkyLight)
|
||||
skyLight = DEFAULT_MAX_LIGHT;
|
||||
else
|
||||
skyLight = serverWorld.getBrightness(LightType.SKY, blockPos);
|
||||
skyLight = world.getSkyLight(blockPos);
|
||||
|
||||
if (!topBlock && skyLight == 15)
|
||||
{
|
||||
@@ -508,8 +427,11 @@ public class LodBuilder
|
||||
}
|
||||
else
|
||||
{
|
||||
world = MinecraftWrapper.INSTANCE.getWrappedClientWorld();
|
||||
if(world.isEmpty())
|
||||
return 0;
|
||||
// client world sky light (almost never accurate)
|
||||
blockLight = clientWorld.getBrightness(LightType.BLOCK, blockPos);
|
||||
blockLight = world.getBlockLight(blockPos);
|
||||
// estimate what the lighting should be
|
||||
if (hasSkyLight || !hasCeiling)
|
||||
{
|
||||
@@ -517,7 +439,7 @@ public class LodBuilder
|
||||
skyLight = DEFAULT_MAX_LIGHT;
|
||||
else
|
||||
{
|
||||
skyLight = clientWorld.getBrightness(LightType.SKY, blockPos);
|
||||
skyLight = world.getSkyLight(blockPos);
|
||||
if (!chunk.isLightCorrect() && (skyLight == 0 || skyLight == 15))
|
||||
{
|
||||
// we don't know what the light here is,
|
||||
@@ -539,147 +461,8 @@ public class LodBuilder
|
||||
return blockLight + (skyLight << 4) + (isDefault << 8);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate the color of the given block from its texture
|
||||
* and store it for later use.
|
||||
*/
|
||||
private int getColorTextureForBlock(BlockState blockState, BlockPos blockPos, boolean useTopTexture)
|
||||
{
|
||||
// use the pre-generated color if we can
|
||||
Block block = blockState.getBlock();
|
||||
if (colorMap.containsKey(block) && toTint.containsKey(block))
|
||||
return colorMap.get(block);
|
||||
|
||||
World world = mc.getClientWorld();
|
||||
TextureAtlasSprite texture;
|
||||
List<BakedQuad> quads = null;
|
||||
int tintIndex = Integer.MIN_VALUE;
|
||||
boolean isTinted = false;
|
||||
int listSize = 0;
|
||||
// get the first quad we can for this block
|
||||
for (Direction direction : directions)
|
||||
{
|
||||
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(blockState).getQuads(blockState, direction, new Random(0), dataMap);
|
||||
listSize = Math.max(listSize, quads.size());
|
||||
for (BakedQuad bakedQuad : quads)
|
||||
{
|
||||
isTinted |= bakedQuad.isTinted();
|
||||
tintIndex = Math.max(tintIndex, bakedQuad.getTintIndex());
|
||||
}
|
||||
}
|
||||
toTint.put(block, isTinted);
|
||||
tintColor.put(block, tintIndex);
|
||||
for (Direction direction : directions)
|
||||
{
|
||||
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(blockState).getQuads(blockState, direction, new Random(0), dataMap);
|
||||
if (!quads.isEmpty())
|
||||
break;
|
||||
}
|
||||
|
||||
if (useTopTexture && !quads.isEmpty())
|
||||
texture = quads.get(0).getSprite();
|
||||
else
|
||||
texture = mc.getModelManager().getBlockModelShaper().getTexture(blockState, world, blockPos);
|
||||
|
||||
|
||||
int count = 0;
|
||||
int alpha = 0;
|
||||
int red = 0;
|
||||
int green = 0;
|
||||
int blue = 0;
|
||||
int numberOfGreyPixel = 0;
|
||||
int color;
|
||||
int colorMultiplier;
|
||||
|
||||
// generate the block's color
|
||||
for (int frameIndex = 0; frameIndex < texture.getFrameCount(); frameIndex++)
|
||||
{
|
||||
// textures normally use u and v instead of x and y
|
||||
for (int u = 0; u < texture.getHeight(); u++)
|
||||
{
|
||||
for (int v = 0; v < texture.getWidth(); v++)
|
||||
{
|
||||
if (texture.isTransparent(frameIndex, u, v))
|
||||
continue;
|
||||
|
||||
color = texture.getPixelRGBA(frameIndex, u, v);
|
||||
|
||||
// determine if this pixel is gray
|
||||
int colorMax = Math.max(Math.max(ColorUtil.getBlue(color), ColorUtil.getGreen(color)), ColorUtil.getRed(color));
|
||||
int colorMin = 4 + Math.min(Math.min(ColorUtil.getBlue(color), ColorUtil.getGreen(color)), ColorUtil.getRed(color));
|
||||
boolean isGray = colorMax < colorMin;
|
||||
if (isGray)
|
||||
numberOfGreyPixel++;
|
||||
|
||||
|
||||
// for flowers, weight their non-green color higher
|
||||
if (block instanceof FlowerBlock && (!(ColorUtil.getGreen(color) > (ColorUtil.getBlue(color) + 30)) || !(ColorUtil.getGreen(color) > (ColorUtil.getRed(color) + 30))))
|
||||
colorMultiplier = 5;
|
||||
else
|
||||
colorMultiplier = 1;
|
||||
|
||||
|
||||
// add to the running averages
|
||||
count += colorMultiplier;
|
||||
alpha += ColorUtil.getAlpha(color) * colorMultiplier;
|
||||
red += ColorUtil.getBlue(color) * colorMultiplier;
|
||||
green += ColorUtil.getGreen(color) * colorMultiplier;
|
||||
blue += ColorUtil.getRed(color) * colorMultiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (count == 0)
|
||||
// this block is entirely transparent
|
||||
color = 0;
|
||||
else
|
||||
{
|
||||
// determine the average color
|
||||
alpha /= count;
|
||||
red /= count;
|
||||
green /= count;
|
||||
blue /= count;
|
||||
color = ColorUtil.rgbToInt(alpha, red, green, blue);
|
||||
}
|
||||
|
||||
// determine if this block should use the biome color tint
|
||||
if ((useGrassTint(block) || useLeafTint(block) || useWaterTint(block)) && (float) numberOfGreyPixel / count > 0.75f)
|
||||
toTint.replace(block, true);
|
||||
|
||||
// add the newly generated block color to the map for later use
|
||||
colorMap.put(block, color);
|
||||
return color;
|
||||
}
|
||||
|
||||
/** determine if the given block should use the biome's grass color */
|
||||
private boolean useGrassTint(Block block)
|
||||
{
|
||||
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 useLeafTint(Block block)
|
||||
{
|
||||
return block instanceof LeavesBlock
|
||||
|| block == Blocks.VINE
|
||||
|| block == Blocks.SUGAR_CANE;
|
||||
}
|
||||
|
||||
/** determine if the given block should use the biome's water color */
|
||||
private boolean useWaterTint(Block block)
|
||||
{
|
||||
return block == Blocks.WATER;
|
||||
}
|
||||
|
||||
/** Returns a color int for the given block. */
|
||||
private int getColorForBlock(IChunk chunk, BlockPos blockPos)
|
||||
private int getColorForBlock(ChunkWrapper chunk, BlockPosWrapper blockPos)
|
||||
{
|
||||
|
||||
|
||||
@@ -693,84 +476,39 @@ public class LodBuilder
|
||||
int z = blockPos.getZ();
|
||||
|
||||
//Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, y >> 2, zRel >> 2);
|
||||
BlockState blockState = chunk.getBlockState(blockPos);
|
||||
BlockWrapper block;
|
||||
if (chunk.isWaterLogged(blockPos))
|
||||
block = BlockWrapper.getBlockWrapper(Blocks.WATER);
|
||||
else
|
||||
block = chunk.getBlock(blockPos);
|
||||
|
||||
if(isInWater(blockState))
|
||||
blockState = Blocks.WATER.defaultBlockState();
|
||||
|
||||
// block special cases
|
||||
// TODO: this needs to be replaced by a config file of some sort
|
||||
if (blockState == Blocks.AIR.defaultBlockState()
|
||||
|| blockState == Blocks.CAVE_AIR.defaultBlockState()
|
||||
|| blockState == Blocks.BARRIER.defaultBlockState())
|
||||
if (block.isToAvoid())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
blockColor = getColorTextureForBlock(blockState, blockPos, true);
|
||||
blockColor = block.getColor();
|
||||
|
||||
//if the blockColor is 0 we reset it and don't use the faceColor
|
||||
if (blockColor == 0)
|
||||
{
|
||||
tintColor.remove(blockState.getBlock());
|
||||
toTint.remove(blockState.getBlock());
|
||||
colorMap.remove(blockState.getBlock());
|
||||
blockColor = getColorTextureForBlock(blockState, blockPos, false);
|
||||
}
|
||||
|
||||
//if the blockColor is still 0 we use the default material color
|
||||
if (blockColor == 0)
|
||||
if (block.hasTint())
|
||||
{
|
||||
tintColor.replace(blockState.getBlock(), 0);
|
||||
toTint.replace(blockState.getBlock(), false);
|
||||
colorMap.replace(blockState.getBlock(), blockState.getBlock().defaultMaterialColor().col);
|
||||
}
|
||||
|
||||
if (toTint.get(blockState.getBlock()))
|
||||
{
|
||||
Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, y >> 2, zRel >> 2);
|
||||
|
||||
ClientWorld clientWorld = mc.getClientWorld();
|
||||
if (clientWorld == null)
|
||||
return 0;
|
||||
ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(clientWorld.dimensionType());
|
||||
BiomeWrapper biome = chunk.getBiome(xRel, y, zRel);
|
||||
|
||||
int tintValue;
|
||||
if (useGrassTint(blockState.getBlock()))
|
||||
if (block.hasGrassTint())
|
||||
{
|
||||
// grass and green plants
|
||||
try
|
||||
{
|
||||
tintValue = BiomeColors.getAverageGrassColor(serverWorld, blockPos);
|
||||
}
|
||||
catch(NullPointerException e)
|
||||
{
|
||||
tintValue = biome.getGrassColor(x, z);
|
||||
}
|
||||
tintValue = biome.getGrassTint(x, z);
|
||||
}
|
||||
else if (useWaterTint(blockState.getBlock()))
|
||||
else if (block.hasFolliageTint())
|
||||
{
|
||||
// water
|
||||
try
|
||||
{
|
||||
tintValue = BiomeColors.getAverageWaterColor(serverWorld, blockPos);
|
||||
}
|
||||
catch(NullPointerException e)
|
||||
{
|
||||
tintValue = biome.getWaterColor();
|
||||
}
|
||||
tintValue = biome.getFolliageTint();
|
||||
}
|
||||
else
|
||||
{
|
||||
// leaves
|
||||
try
|
||||
{
|
||||
tintValue = BiomeColors.getAverageFoliageColor(serverWorld, blockPos);
|
||||
}
|
||||
catch(NullPointerException e)
|
||||
{
|
||||
tintValue = biome.getFoliageColor();
|
||||
}
|
||||
//we can reintroduce this with the wrappers
|
||||
//tintValue = BiomeColors.getAverageFoliageColor(serverWorld, blockPos);
|
||||
tintValue = biome.getWaterTint();
|
||||
}
|
||||
colorInt = ColorUtil.multiplyRGBcolors(tintValue | 0xFF000000, blockColor);
|
||||
}
|
||||
@@ -779,164 +517,23 @@ public class LodBuilder
|
||||
return colorInt;
|
||||
}
|
||||
|
||||
/** Returns a color int for the given biome. */
|
||||
private int getColorForBiome(int x, int z, Biome biome)
|
||||
{
|
||||
int colorInt;
|
||||
|
||||
switch (biome.getBiomeCategory())
|
||||
{
|
||||
|
||||
case NETHER:
|
||||
colorInt = Blocks.NETHERRACK.defaultBlockState().materialColor.col;
|
||||
break;
|
||||
|
||||
case THEEND:
|
||||
colorInt = Blocks.END_STONE.defaultBlockState().materialColor.col;
|
||||
break;
|
||||
|
||||
case BEACH:
|
||||
case DESERT:
|
||||
colorInt = Blocks.SAND.defaultBlockState().materialColor.col;
|
||||
break;
|
||||
|
||||
case EXTREME_HILLS:
|
||||
colorInt = Blocks.STONE.defaultMaterialColor().col;
|
||||
break;
|
||||
|
||||
case MUSHROOM:
|
||||
colorInt = MaterialColor.COLOR_LIGHT_GRAY.col;
|
||||
break;
|
||||
|
||||
case ICY:
|
||||
colorInt = Blocks.SNOW.defaultMaterialColor().col;
|
||||
break;
|
||||
|
||||
case MESA:
|
||||
colorInt = Blocks.RED_SAND.defaultMaterialColor().col;
|
||||
break;
|
||||
|
||||
case OCEAN:
|
||||
case RIVER:
|
||||
colorInt = biome.getWaterColor();
|
||||
break;
|
||||
|
||||
case NONE:
|
||||
case FOREST:
|
||||
case TAIGA:
|
||||
case JUNGLE:
|
||||
case PLAINS:
|
||||
case SAVANNA:
|
||||
case SWAMP:
|
||||
default:
|
||||
Color tmp = LodUtil.intToColor(biome.getGrassColor(x, z));
|
||||
tmp = tmp.darker();
|
||||
colorInt = LodUtil.colorToInt(tmp);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return colorInt;
|
||||
}
|
||||
|
||||
private boolean isInWater(BlockState blockState)
|
||||
{
|
||||
//This type of block is always in water
|
||||
if((blockState.getBlock() instanceof ILiquidContainer) && !(blockState.getBlock() instanceof IWaterLoggable))
|
||||
return true;
|
||||
|
||||
//This type of block could be in water
|
||||
if(blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).isPresent() && blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).get())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Is the block at the given blockPos a valid LOD point? */
|
||||
private boolean isLayerValidLodPoint(IChunk chunk, BlockPos.Mutable blockPos)
|
||||
private boolean isLayerValidLodPoint(ChunkWrapper chunk, BlockPosWrapper blockPos)
|
||||
{
|
||||
|
||||
BlockState blockState = chunk.getBlockState(blockPos);
|
||||
|
||||
if (isInWater(blockState))
|
||||
if (chunk.isWaterLogged(blockPos))
|
||||
return true;
|
||||
|
||||
boolean nonFullAvoidance = LodConfig.CLIENT.worldGenerator.blockToAvoid.get().nonFull;
|
||||
boolean noCollisionAvoidance = LodConfig.CLIENT.worldGenerator.blockToAvoid.get().noCollision;
|
||||
if (blockState != null)
|
||||
{
|
||||
if (nonFullAvoidance)
|
||||
{
|
||||
if(!blockState.getFluidState().isEmpty() || blockState.getBlock() instanceof SixWayBlock)
|
||||
{
|
||||
notFullBlock.put(blockState.getBlock(), false);
|
||||
}
|
||||
if (!notFullBlock.containsKey(blockState.getBlock()) || notFullBlock.get(blockState.getBlock()) == null)
|
||||
{
|
||||
VoxelShape voxelShape = blockState.getBlock().defaultBlockState().getShape(chunk, blockPos);
|
||||
|
||||
if (!voxelShape.isEmpty())
|
||||
{
|
||||
AxisAlignedBB bbox = voxelShape.bounds();
|
||||
double xWidth = (bbox.maxX - bbox.minX);
|
||||
double yWidth = (bbox.maxY - bbox.minY);
|
||||
double zWidth = (bbox.maxZ - bbox.minZ);
|
||||
if (xWidth < 1 && zWidth < 1 && yWidth < 1)
|
||||
notFullBlock.put(blockState.getBlock(), true);
|
||||
else
|
||||
notFullBlock.put(blockState.getBlock(), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
notFullBlock.put(blockState.getBlock(), false);
|
||||
}
|
||||
}
|
||||
|
||||
if (notFullBlock.get(blockState.getBlock()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (noCollisionAvoidance)
|
||||
{
|
||||
if(!blockState.getFluidState().isEmpty() || blockState.getBlock() instanceof SixWayBlock)
|
||||
smallBlock.put(blockState.getBlock(), false);
|
||||
|
||||
if (!smallBlock.containsKey(blockState.getBlock()) || smallBlock.get(blockState.getBlock()) == null)
|
||||
{
|
||||
VoxelShape voxelShape = blockState.getCollisionShape(chunk, blockPos);
|
||||
if (!blockState.getFluidState().isEmpty())
|
||||
{
|
||||
smallBlock.put(blockState.getBlock(), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (voxelShape.isEmpty())
|
||||
{
|
||||
smallBlock.put(blockState.getBlock(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
smallBlock.put(blockState.getBlock(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (smallBlock.get(blockState.getBlock()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return blockState.getBlock() != Blocks.AIR
|
||||
&& blockState.getBlock() != Blocks.CAVE_AIR
|
||||
&& blockState.getBlock() != Blocks.BARRIER;
|
||||
}
|
||||
|
||||
return false;
|
||||
boolean nonFullAvoidance = LodConfig.CLIENT.worldGenerator.blockToAvoid.get().nonFull;
|
||||
boolean noCollisionAvoidance = LodConfig.CLIENT.worldGenerator.blockToAvoid.get().noCollision;
|
||||
|
||||
BlockWrapper block = chunk.getBlock(blockPos);
|
||||
return block != null
|
||||
&& !block.isToAvoid()
|
||||
&& !(nonFullAvoidance && block.isNonFull())
|
||||
&& !(noCollisionAvoidance && block.hasNoCollision());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.seibel.lod.objects.LodDimension;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
@@ -384,7 +385,7 @@ public class LodGenWorker implements IWorker
|
||||
|
||||
if (!inTheEnd)
|
||||
{
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(true, true, false));
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(true, true, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -392,7 +393,7 @@ public class LodGenWorker implements IWorker
|
||||
// Since we don't know where the islands are, everything
|
||||
// generates the same, and it looks awful.
|
||||
//TODO it appears that 'if' can be collapsed, but comment says that it should not be a case
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(true, true, false));
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(true, true, false));
|
||||
}
|
||||
|
||||
|
||||
@@ -432,7 +433,7 @@ public class LodGenWorker implements IWorker
|
||||
snowFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition(), null);
|
||||
|
||||
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(DistanceGenerationMode.SURFACE));
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(DistanceGenerationMode.SURFACE));
|
||||
|
||||
/*TODO if we want to use Biome utils and terrain utils for overworld
|
||||
* lodBuilder.generateLodNodeFromChunk(lodDim, pos ,detailLevel, serverWorld.getSeed());*/
|
||||
@@ -558,7 +559,7 @@ public class LodGenWorker implements IWorker
|
||||
}
|
||||
|
||||
// generate a Lod like normal
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, chunk, new LodBuilderConfig(DistanceGenerationMode.FEATURES));
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(chunk), new LodBuilderConfig(DistanceGenerationMode.FEATURES));
|
||||
}
|
||||
|
||||
|
||||
@@ -573,7 +574,7 @@ public class LodGenWorker implements IWorker
|
||||
*/
|
||||
private void generateWithServer()
|
||||
{
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, serverWorld.getChunk(pos.x, pos.z, ChunkStatus.FEATURES), new LodBuilderConfig(DistanceGenerationMode.SERVER));
|
||||
lodBuilder.generateLodNodeFromChunk(lodDim, new ChunkWrapper(serverWorld.getChunk(pos.x, pos.z, ChunkStatus.FEATURES)), new LodBuilderConfig(DistanceGenerationMode.SERVER));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.seibel.lod.proxy;
|
||||
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
@@ -213,7 +214,7 @@ public class ClientProxy
|
||||
@SubscribeEvent
|
||||
public void chunkLoadEvent(ChunkEvent.Load event)
|
||||
{
|
||||
lodBuilder.generateLodNodeAsync(event.getChunk(), lodWorld, event.getWorld(), DistanceGenerationMode.SERVER);
|
||||
lodBuilder.generateLodNodeAsync(new ChunkWrapper(event.getChunk()), lodWorld, event.getWorld(), DistanceGenerationMode.SERVER);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -283,7 +284,7 @@ public class ClientProxy
|
||||
event.getClass() == BlockEvent.PortalSpawnEvent.class)
|
||||
{
|
||||
// recreate the LOD where the blocks were changed
|
||||
lodBuilder.generateLodNodeAsync(event.getWorld().getChunk(event.getPos()), lodWorld, event.getWorld());
|
||||
lodBuilder.generateLodNodeAsync(new ChunkWrapper(event.getWorld().getChunk(event.getPos())), lodWorld, event.getWorld());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ public class BlockPosWrapper
|
||||
|
||||
public BlockPosWrapper()
|
||||
{
|
||||
this.blockPos = new BlockPos.Mutable();
|
||||
this.blockPos = new BlockPos.Mutable(0,0,0);
|
||||
}
|
||||
|
||||
public void set(int x, int y, int z)
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package com.seibel.lod.wrappers.Block;
|
||||
|
||||
import com.seibel.lod.util.ColorUtil;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraftforge.client.model.data.ModelDataMap;
|
||||
|
||||
import java.util.*;
|
||||
@@ -23,19 +28,31 @@ public class BlockWrapper
|
||||
|
||||
|
||||
private Block block;
|
||||
private boolean toAvoid;
|
||||
private boolean nonFull;
|
||||
private boolean noCollision;
|
||||
private int color;
|
||||
private boolean isColored;
|
||||
private boolean toTint;
|
||||
private boolean leavesTint;
|
||||
private boolean folliageTint;
|
||||
private boolean grassTint;
|
||||
private boolean waterTint;
|
||||
|
||||
|
||||
|
||||
/**Constructor only require for the block instance we are wrapping**/
|
||||
public BlockWrapper(Block block)
|
||||
{
|
||||
this.nonFull = false;
|
||||
this.noCollision = false;
|
||||
this.color = 0;
|
||||
this.isColored = true;
|
||||
this.toTint = false;
|
||||
this.block = block;
|
||||
setupColorAndTint();
|
||||
}
|
||||
|
||||
/**Constructor only require for the block instance we are wrapping**/
|
||||
public BlockWrapper(Block block, ChunkWrapper chunkWrapper, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
this.nonFull = true;
|
||||
this.noCollision = true;
|
||||
@@ -44,7 +61,7 @@ public class BlockWrapper
|
||||
this.toTint = false;
|
||||
this.block = block;
|
||||
setupColorAndTint();
|
||||
setupShapes();
|
||||
setupShapes(chunkWrapper, blockPosWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +71,7 @@ public class BlockWrapper
|
||||
static public BlockWrapper getBlockWrapper(Block block)
|
||||
{
|
||||
//first we check if the block has already been wrapped
|
||||
if(blockWrapperMap.containsKey(block) && blockWrapperMap.get(block) != null)
|
||||
if (blockWrapperMap.containsKey(block) && blockWrapperMap.get(block) != null)
|
||||
return blockWrapperMap.get(block);
|
||||
|
||||
|
||||
@@ -66,6 +83,25 @@ public class BlockWrapper
|
||||
return blockWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* this return a wrapper of the block in input
|
||||
* @param block Block object to wrap
|
||||
*/
|
||||
static public BlockWrapper getBlockWrapper(Block block, ChunkWrapper chunkWrapper, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
//first we check if the block has already been wrapped
|
||||
if (blockWrapperMap.containsKey(block) && blockWrapperMap.get(block) != null)
|
||||
return blockWrapperMap.get(block);
|
||||
|
||||
|
||||
//if it hasn't been created yet, we create it and save it in the map
|
||||
BlockWrapper blockWrapper = new BlockWrapper(block, chunkWrapper, blockPosWrapper);
|
||||
blockWrapperMap.put(block, blockWrapper);
|
||||
|
||||
//we return the newly created wrapper
|
||||
return blockWrapper;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate the color of the given block from its texture
|
||||
@@ -92,7 +128,7 @@ public class BlockWrapper
|
||||
}
|
||||
|
||||
//if it contains a tinted face then we store this block in the toTint set
|
||||
if(isTinted)
|
||||
if (isTinted)
|
||||
this.toTint = true;
|
||||
|
||||
//now we get the first non empty face
|
||||
@@ -181,7 +217,7 @@ public class BlockWrapper
|
||||
this.grassTint = true;
|
||||
|
||||
if (leavesInstance() && this.toTint)
|
||||
this.leavesTint = true;
|
||||
this.folliageTint = true;
|
||||
|
||||
if (waterIstance() && this.toTint)
|
||||
this.waterTint = true;
|
||||
@@ -214,13 +250,58 @@ public class BlockWrapper
|
||||
return block == Blocks.WATER;
|
||||
}
|
||||
|
||||
private void setupShapes(){
|
||||
|
||||
private void setupShapes(ChunkWrapper chunkWrapper, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
IBlockReader chunk = chunkWrapper.getChunk();
|
||||
BlockPos blockPos = blockPosWrapper.getBlockPos();
|
||||
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())
|
||||
{
|
||||
AxisAlignedBB bbox = voxelShape.bounds();
|
||||
double xWidth = (bbox.maxX - bbox.minX);
|
||||
double yWidth = (bbox.maxY - bbox.minY);
|
||||
double zWidth = (bbox.maxZ - bbox.minZ);
|
||||
if (xWidth < 1 && zWidth < 1 && yWidth < 1)
|
||||
nonFull = true;
|
||||
else
|
||||
nonFull = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nonFull = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!noCollisionSetted)
|
||||
{
|
||||
VoxelShape collisionShape = block.defaultBlockState().getCollisionShape(chunk, blockPos);
|
||||
noCollision = collisionShape.isEmpty();
|
||||
}
|
||||
|
||||
toAvoid = ofBlockToAvoid(block);
|
||||
}
|
||||
|
||||
//--------------//
|
||||
//Colors getters//
|
||||
//--------------//
|
||||
private boolean ofBlockToAvoid(Block block)
|
||||
{
|
||||
return block == Blocks.AIR
|
||||
|| block != Blocks.CAVE_AIR
|
||||
|| block != Blocks.BARRIER;
|
||||
}
|
||||
//--------------//
|
||||
//Colors getters//
|
||||
//--------------//
|
||||
|
||||
public boolean hasColor()
|
||||
{
|
||||
@@ -229,12 +310,15 @@ public class BlockWrapper
|
||||
|
||||
public int getColor()
|
||||
{
|
||||
return color;
|
||||
if(hasColor())
|
||||
return color;
|
||||
else
|
||||
return block.defaultMaterialColor().col;
|
||||
}
|
||||
|
||||
//------------//
|
||||
//Tint getters//
|
||||
//------------//
|
||||
|
||||
//------------//
|
||||
//Tint getters//
|
||||
//------------//
|
||||
|
||||
|
||||
public boolean hasTint()
|
||||
@@ -247,9 +331,9 @@ public class BlockWrapper
|
||||
return grassTint;
|
||||
}
|
||||
|
||||
public boolean hasLeavesTint()
|
||||
public boolean hasFolliageTint()
|
||||
{
|
||||
return leavesTint;
|
||||
return folliageTint;
|
||||
}
|
||||
|
||||
public boolean hasWaterTint()
|
||||
@@ -258,6 +342,29 @@ public class BlockWrapper
|
||||
}
|
||||
|
||||
|
||||
//-----------------//
|
||||
//Avoidance getters//
|
||||
//-----------------//
|
||||
|
||||
|
||||
public boolean isNonFull()
|
||||
{
|
||||
return nonFull;
|
||||
}
|
||||
|
||||
public boolean hasNoCollision()
|
||||
{
|
||||
return noCollision;
|
||||
}
|
||||
|
||||
public boolean isToAvoid()
|
||||
{
|
||||
return folliageTint;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
|
||||
@@ -26,6 +26,26 @@ public class ChunkPosWrapper
|
||||
return chunkPos.z;
|
||||
}
|
||||
|
||||
public int getMinBlockX()
|
||||
{
|
||||
return chunkPos.getMinBlockX();
|
||||
}
|
||||
|
||||
public int getMinBlockZ()
|
||||
{
|
||||
return chunkPos.getMinBlockZ();
|
||||
}
|
||||
|
||||
public int getRegionX()
|
||||
{
|
||||
return chunkPos.getRegionX();
|
||||
}
|
||||
|
||||
public int getRegionZ()
|
||||
{
|
||||
return chunkPos.getRegionZ();
|
||||
}
|
||||
|
||||
public ChunkPos getChunkPos()
|
||||
{
|
||||
return chunkPos;
|
||||
|
||||
@@ -1,29 +1,93 @@
|
||||
package com.seibel.lod.wrappers.Chunk;
|
||||
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.Block.BlockWrapper;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import com.seibel.lod.wrappers.World.BiomeWrapper;
|
||||
import com.sun.javafx.scene.control.behavior.OptionalBoolean;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.ILiquidContainer;
|
||||
import net.minecraft.block.IWaterLoggable;
|
||||
import net.minecraft.loot.conditions.BlockStateProperty;
|
||||
import net.minecraft.state.Property;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.chunk.IChunk;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class ChunkWrapper
|
||||
{
|
||||
|
||||
private IChunk chunk;
|
||||
private ChunkPosWrapper chunkPos;
|
||||
|
||||
public int getHeight(){
|
||||
return chunk.getMaxBuildHeight();
|
||||
}
|
||||
|
||||
public boolean isPositionInWater(BlockPosWrapper blockPos)
|
||||
{
|
||||
BlockState blockState = chunk.getBlockState(blockPos.getBlockPos());
|
||||
|
||||
//This type of block is always in water
|
||||
if((blockState.getBlock() instanceof ILiquidContainer) && !(blockState.getBlock() instanceof IWaterLoggable))
|
||||
return true;
|
||||
|
||||
//This type of block could be in water
|
||||
if(blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).isPresent() && blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).get())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getHeightMapValue(int xRel, int zRel){
|
||||
return chunk.getOrCreateHeightmapUnprimed(LodUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
|
||||
}
|
||||
|
||||
public BiomeWrapper getBiome(int xRel, int yAbs, int zRel)
|
||||
{
|
||||
return BiomeWrapper.getBiomeWrapper(chunk.getBiomes().getNoiseBiome(xRel >> 2, yAbs >> 2, zRel >> 2));
|
||||
}
|
||||
|
||||
public BlockWrapper getBlock(BlockPosWrapper blockPos)
|
||||
{
|
||||
return BlockWrapper.getBlockWrapper(chunk.getBlockState(blockPos.getBlockPos()).getBlock(), this, blockPos);
|
||||
}
|
||||
|
||||
|
||||
public ChunkWrapper(IChunk chunk)
|
||||
{
|
||||
this.chunk = chunk;
|
||||
this.chunkPos = new ChunkPosWrapper(chunk.getPos());
|
||||
}
|
||||
|
||||
public BlockWrapper getBlock(BlockPosWrapper blockPos)
|
||||
{
|
||||
return BlockWrapper.getBlockWrapper(chunk.getBlockState(blockPos.getBlockPos()).getBlock());
|
||||
public IChunk getChunk(){
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public ChunkPosWrapper getChunkPos(){
|
||||
public ChunkPosWrapper getPos(){
|
||||
return chunkPos;
|
||||
}
|
||||
|
||||
public boolean isLightCorrect(){
|
||||
return chunk.isLightCorrect();
|
||||
}
|
||||
|
||||
public boolean
|
||||
isWaterLogged(BlockPosWrapper blockPos)
|
||||
{
|
||||
BlockState blockState = chunk.getBlockState(blockPos.getBlockPos());
|
||||
|
||||
//This type of block is always in water
|
||||
if((blockState.getBlock() instanceof ILiquidContainer) && !(blockState.getBlock() instanceof IWaterLoggable))
|
||||
return true;
|
||||
|
||||
//This type of block could be in water
|
||||
if(blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).isPresent() && blockState.getOptionalValue(BlockStateProperties.WATERLOGGED).get())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getEmittedBrightness(BlockPosWrapper blockPos)
|
||||
{
|
||||
return chunk.getLightEmission(blockPos.getBlockPos());
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.seibel.lod.ModInfo;
|
||||
import com.seibel.lod.proxy.ClientProxy;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
|
||||
import com.seibel.lod.wrappers.World.WorldWrapper;
|
||||
import net.minecraft.client.GameSettings;
|
||||
import net.minecraft.client.MainWindow;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -44,6 +45,7 @@ import net.minecraft.profiler.IProfiler;
|
||||
import net.minecraft.server.integrated.IntegratedServer;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
/**
|
||||
* A singleton that wraps the Minecraft class
|
||||
@@ -183,6 +185,36 @@ public class MinecraftWrapper
|
||||
return mc.level;
|
||||
}
|
||||
|
||||
public WorldWrapper getWrappedClientWorld()
|
||||
{
|
||||
return WorldWrapper.getWorldWrapper(mc.level);
|
||||
}
|
||||
|
||||
public WorldWrapper getWrappedServerWorld()
|
||||
{
|
||||
|
||||
if (mc.level == null)
|
||||
return null;
|
||||
DimensionType dimension = mc.level.dimensionType();
|
||||
IntegratedServer server = mc.getSingleplayerServer();
|
||||
if (server == null)
|
||||
return null;
|
||||
|
||||
Iterable<ServerWorld> worlds = server.getAllLevels();
|
||||
ServerWorld returnWorld = null;
|
||||
|
||||
for (ServerWorld world : worlds)
|
||||
{
|
||||
if (world.dimensionType() == dimension)
|
||||
{
|
||||
returnWorld = world;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return WorldWrapper.getWorldWrapper(returnWorld);
|
||||
}
|
||||
|
||||
/** Measured in chunks */
|
||||
public int getRenderDistance()
|
||||
{
|
||||
|
||||
@@ -115,6 +115,22 @@ public class BiomeWrapper
|
||||
return colorInt;
|
||||
}
|
||||
|
||||
public int getGrassTint(int x, int z)
|
||||
{
|
||||
return biome.getGrassColor(x, z);
|
||||
}
|
||||
|
||||
public int getFolliageTint()
|
||||
{
|
||||
return biome.getFoliageColor();
|
||||
}
|
||||
|
||||
public int getWaterTint()
|
||||
{
|
||||
return biome.getWaterColor();
|
||||
}
|
||||
|
||||
|
||||
@Override public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
|
||||
@@ -16,7 +16,8 @@ public class WorldWrapper
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public WorldWrapper getWorldWrapper(IWorld world)
|
||||
|
||||
public static WorldWrapper getWorldWrapper(IWorld world)
|
||||
{
|
||||
//first we check if the biome has already been wrapped
|
||||
if(worldWrapperMap.containsKey(world) && worldWrapperMap.get(world) != null)
|
||||
@@ -65,4 +66,9 @@ public class WorldWrapper
|
||||
{
|
||||
return world.dimensionType().hasSkyLight();
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return world == null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user