From 12a32b9fb4addbcb737c191fd7938edc6b9edece Mon Sep 17 00:00:00 2001 From: Leonardo Date: Tue, 26 Oct 2021 11:58:33 +0200 Subject: [PATCH] Implemented the wrappers in the lodBuilder --- .../lod/builders/lodBuilding/LodBuilder.java | 569 +++--------------- .../worldGeneration/LodGenWorker.java | 11 +- .../com/seibel/lod/proxy/ClientProxy.java | 5 +- .../lod/wrappers/Block/BlockPosWrapper.java | 2 +- .../lod/wrappers/Block/BlockWrapper.java | 143 ++++- .../lod/wrappers/Chunk/ChunkPosWrapper.java | 20 + .../lod/wrappers/Chunk/ChunkWrapper.java | 74 ++- .../seibel/lod/wrappers/MinecraftWrapper.java | 32 + .../lod/wrappers/World/BiomeWrapper.java | 16 + .../lod/wrappers/World/WorldWrapper.java | 8 +- 10 files changed, 362 insertions(+), 518 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java index 152f58efa..ff1d8444a 100644 --- a/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java +++ b/src/main/java/com/seibel/lod/builders/lodBuilding/LodBuilder.java @@ -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 colorMap = new ConcurrentHashMap<>(); - public static final ConcurrentMap tintColor = new ConcurrentHashMap<>(); - public static final ConcurrentMap toTint = new ConcurrentHashMap<>(); - - public static final ConcurrentMap notFullBlock = new ConcurrentHashMap<>(); - public static final ConcurrentMap 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 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()); + } } diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java index 75b5ef576..7787664e7 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodGenWorker.java @@ -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)); } diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index 644531783..139f3ef8c 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -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()); } } diff --git a/src/main/java/com/seibel/lod/wrappers/Block/BlockPosWrapper.java b/src/main/java/com/seibel/lod/wrappers/Block/BlockPosWrapper.java index 270b8b25a..6dd9d0f20 100644 --- a/src/main/java/com/seibel/lod/wrappers/Block/BlockPosWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/Block/BlockPosWrapper.java @@ -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) diff --git a/src/main/java/com/seibel/lod/wrappers/Block/BlockWrapper.java b/src/main/java/com/seibel/lod/wrappers/Block/BlockWrapper.java index 0f5bb38aa..767607096 100644 --- a/src/main/java/com/seibel/lod/wrappers/Block/BlockWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/Block/BlockWrapper.java @@ -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) diff --git a/src/main/java/com/seibel/lod/wrappers/Chunk/ChunkPosWrapper.java b/src/main/java/com/seibel/lod/wrappers/Chunk/ChunkPosWrapper.java index 5fc84f5eb..88ae081ac 100644 --- a/src/main/java/com/seibel/lod/wrappers/Chunk/ChunkPosWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/Chunk/ChunkPosWrapper.java @@ -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; diff --git a/src/main/java/com/seibel/lod/wrappers/Chunk/ChunkWrapper.java b/src/main/java/com/seibel/lod/wrappers/Chunk/ChunkWrapper.java index 084db34e1..b8eac2382 100644 --- a/src/main/java/com/seibel/lod/wrappers/Chunk/ChunkWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/Chunk/ChunkWrapper.java @@ -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()); diff --git a/src/main/java/com/seibel/lod/wrappers/MinecraftWrapper.java b/src/main/java/com/seibel/lod/wrappers/MinecraftWrapper.java index 67f2297fe..8c7c2fcd6 100644 --- a/src/main/java/com/seibel/lod/wrappers/MinecraftWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/MinecraftWrapper.java @@ -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 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() { diff --git a/src/main/java/com/seibel/lod/wrappers/World/BiomeWrapper.java b/src/main/java/com/seibel/lod/wrappers/World/BiomeWrapper.java index f14485f8c..42c1a4c59 100644 --- a/src/main/java/com/seibel/lod/wrappers/World/BiomeWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/World/BiomeWrapper.java @@ -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) diff --git a/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java b/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java index 4589c225a..79dddee46 100644 --- a/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java +++ b/src/main/java/com/seibel/lod/wrappers/World/WorldWrapper.java @@ -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; + } }