registerRenderer(BoundingBoxLine.class, new LineRenderer());
registerRenderer(BoundingBoxSphere.class, new SphereRenderer());
registerRenderer(BoundingBoxFlowerForest.class, new FlowerForestRenderer());
+ registerRenderer(BoundingBoxBedrockCeiling.class, new CuboidRenderer());
registerProvider(new SlimeChunkProvider());
registerProvider(new WorldSpawnProvider());
registerProvider(new CustomLineProvider());
registerProvider(new CustomSphereProvider());
registerProvider(new FlowerForestProvider());
+ registerProvider(new BedrockCeilingProvider());
}
public static <T extends AbstractBoundingBox> void registerProvider(IBoundingBoxProvider<T> provider) {
registerType(BoundingBoxType.Conduit, ConfigManager.drawConduits, ConfigManager.colorConduits);
registerType(BoundingBoxType.SpawnableBlocks, ConfigManager.drawSpawnableBlocks, ConfigManager.colorSpawnableBlocks);
registerType(BoundingBoxType.FlowerForest, ConfigManager.drawFlowerForests, null);
+ registerType(BoundingBoxType.BedrockCeiling, ConfigManager.drawBedrockCeilingBlocks, ConfigManager.colorBedrockCeilingBlocks);
registerType(BoundingBoxType.JungleTemple, ConfigManager.drawJungleTemples, ConfigManager.colorJungleTemples);
registerType(BoundingBoxType.DesertTemple, ConfigManager.drawDesertTemples, ConfigManager.colorDesertTemples);
public static Setting<Boolean> renderSphereAsDots;
public static Setting<Boolean> drawFlowerForests;
public static Setting<Integer> flowerForestsRenderDistance;
+ public static Setting<Boolean> drawBedrockCeilingBlocks;
public static Setting<HexColor> colorWorldSpawn;
public static Setting<HexColor> colorLazySpawnChunks;
public static Setting<HexColor> colorFlowerForestOxeyeDaisy;
public static Setting<HexColor> colorFlowerForestCornflower;
public static Setting<HexColor> colorFlowerForestLilyOfTheValley;
+ public static Setting<HexColor> colorBedrockCeilingBlocks;
public static Setting<HexColor> buttonOnOverlay;
drawFlowerForests = setup(config, "flowerForests", "drawFlowerForests", true, "If set to true flower forest flower overlays will be drawn.");
flowerForestsRenderDistance = setup(config, "flowerForests", "flowerForestsRenderDistance", 3, "The distance from the player where flower forests will be drawn.");
+ drawBedrockCeilingBlocks = setup(config, "bedrockCeiling", "drawBedrockCeilingBlocks", true, "If set to true position with only one layer of bedrock will be drawn.");
+
drawVillages = setup(config, "structures", "drawVillages", false, "If set to true village bounding boxes will be drawn.");
drawDesertTemples = setup(config, "structures", "drawDesertTemples", true, "If set to true desert temple bounding boxes are drawn.");
drawJungleTemples = setup(config, "structures", "drawJungleTemples", true, "If set to true jungle temple bounding boxes are drawn.");
colorFlowerForestOxeyeDaisy = setup(config, "colors", "colorFlowerForestOxeyeDaisy", HexColor.from("#d3d3d3"), "Color of Flower Forest Oxeye Daisy");
colorFlowerForestCornflower = setup(config, "colors", "colorFlowerForestCornflower", HexColor.from("#0000ff"), "Color of Flower Forest Cornflower");
colorFlowerForestLilyOfTheValley = setup(config, "colors", "colorFlowerForestLilyOfTheValley", HexColor.from("#ffffff"), "Color of Flower Forest Lily Of The Valley");
-
+ colorBedrockCeilingBlocks = setup(config, "colors", "colorBedrockCeilingBlocks", HexColor.from("#00ff00"), "Color of Bedrock Ceiling Blocks");
config.save();
}
--- /dev/null
+package com.irtimaled.bbor.client.interop;
+
+import net.minecraft.block.BlockState;
+import net.minecraft.block.Blocks;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.SharedSeedRandom;
+import net.minecraft.util.math.BlockPos;
+
+import java.util.Random;
+
+public class BedrockCeilingHelper {
+ public static boolean isBedrock(int x, int y, int z){
+ BlockPos pos = new BlockPos(x, y, z);
+ BlockState blockState = Minecraft.getInstance().world.getBlockState(pos);
+ return blockState == Blocks.BEDROCK.getDefaultState();
+ }
+
+ public static boolean chunkLoaded(int chunkX, int chunkZ) {
+ return Minecraft.getInstance().world.getChunkProvider().chunkExists(chunkX, chunkZ);
+ }
+
+ public static Random getRandomForChunk(int chunkX, int chunkZ) {
+ SharedSeedRandom random = new SharedSeedRandom();
+ random.setBaseChunkSeed(chunkX, chunkZ);
+ return random;
+ }
+}
public static void displayScreen(Screen screen) {
Minecraft.getInstance().displayGuiScreen(screen);
}
+
+ public static long getGameTime() {
+ return Minecraft.getInstance().world.getGameTime();
+ }
}
--- /dev/null
+package com.irtimaled.bbor.client.models;
+
+import com.irtimaled.bbor.common.BoundingBoxType;
+import com.irtimaled.bbor.common.models.BoundingBoxCuboid;
+import com.irtimaled.bbor.common.models.Coords;
+
+public class BoundingBoxBedrockCeiling extends BoundingBoxCuboid {
+ public BoundingBoxBedrockCeiling(Coords coords) {
+ super(coords, coords, BoundingBoxType.BedrockCeiling);
+ }
+}
--- /dev/null
+package com.irtimaled.bbor.client.providers;
+
+import com.irtimaled.bbor.client.Player;
+import com.irtimaled.bbor.client.config.BoundingBoxTypeHelper;
+import com.irtimaled.bbor.client.config.ConfigManager;
+import com.irtimaled.bbor.client.interop.BedrockCeilingHelper;
+import com.irtimaled.bbor.client.interop.ClientInterop;
+import com.irtimaled.bbor.client.models.BoundingBoxBedrockCeiling;
+import com.irtimaled.bbor.common.BoundingBoxType;
+import com.irtimaled.bbor.common.MathHelper;
+import com.irtimaled.bbor.common.models.Coords;
+import com.irtimaled.bbor.common.models.DimensionId;
+
+import java.util.*;
+
+public class BedrockCeilingProvider implements IBoundingBoxProvider<BoundingBoxBedrockCeiling>, ICachingProvider {
+ private static final double CHUNK_SIZE = 16d;
+ private static Long lastGameTime = null;
+ private static final Map<String, BedrockChunk> chunks = new HashMap<>();
+
+ private static class BedrockChunk {
+ private final Set<BoundingBoxBedrockCeiling> boxes = new HashSet<>();
+
+ public BedrockChunk(int chunkX, int chunkZ) {
+ int chunkStartX = chunkX << 4;
+ int chunkStartZ = chunkZ << 4;
+
+ if (BedrockCeilingHelper.chunkLoaded(chunkX, chunkZ)) findBoxesFromBlockState(chunkStartX, chunkStartZ);
+ else findBoxesFromRNG(chunkX, chunkZ, chunkStartX, chunkStartZ);
+ }
+
+ private void findBoxesFromBlockState(int chunkStartX, int chunkStartZ) {
+ for (int x = 0; x < 16; x++) {
+ for (int z = 0; z < 16; z++) {
+ Coords coords = getCoordsFromBlockState(chunkStartX + x, chunkStartZ + z);
+ if (coords != null) {
+ boxes.add(new BoundingBoxBedrockCeiling(coords));
+ }
+ }
+ }
+ }
+
+ private Coords getCoordsFromBlockState(int x, int z) {
+ Coords coords = null;
+ for (int y = 127; y >= 123; y--) {
+ if (BedrockCeilingHelper.isBedrock(x, y, z)) {
+ if (coords == null) {
+ coords = new Coords(x, y, z);
+ } else {
+ return null;
+ }
+ }
+ }
+ return coords;
+ }
+
+ private void findBoxesFromRNG(int chunkX, int chunkZ, int chunkStartX, int chunkStartZ) {
+ Random random = BedrockCeilingHelper.getRandomForChunk(chunkX, chunkZ);
+
+ // preseed 16x16x3 calls to nextDouble
+ for (int dummy = 0; dummy < 768; dummy++) {
+ random.nextDouble();
+ }
+ for (int z = 0; z < 16; z++) {
+ for (int x = 0; x < 16; x++) {
+ Coords coords = getBlocksFromRNG(random, chunkStartX + x, chunkStartZ + z);
+
+ if (coords != null) {
+ boxes.add(new BoundingBoxBedrockCeiling(coords));
+ }
+ }
+ }
+ }
+
+ private Coords getBlocksFromRNG(Random random, int x, int z) {
+ int count = 0;
+ for (int y = 127; y >= 123; y--) {
+ if (y >= 127 - random.nextInt(5)) {
+ count++;
+ }
+ }
+ for (int y = 4; y >= 0; y--) {
+ random.nextInt(5);
+ }
+ return count == 1 ? new Coords(x, 127, z) : null;
+ }
+
+ public Collection<? extends BoundingBoxBedrockCeiling> getBlocks() {
+ return boxes;
+ }
+
+ public void clear() {
+ boxes.clear();
+ }
+ }
+
+ public void clearCache() {
+ chunks.values().forEach(BedrockChunk::clear);
+ chunks.clear();
+ }
+
+ @Override
+ public Iterable<BoundingBoxBedrockCeiling> get(DimensionId dimensionId) {
+ boolean shouldRecalculate = shouldRecalculate();
+
+ int renderDistanceChunks = ClientInterop.getRenderDistanceChunks() / 2;
+ int playerChunkX = MathHelper.floor(Player.getX() / CHUNK_SIZE);
+ int playerChunkZ = MathHelper.floor(Player.getZ() / CHUNK_SIZE);
+
+ Set<BoundingBoxBedrockCeiling> boxes = new HashSet<>();
+
+ for (int chunkX = playerChunkX - renderDistanceChunks; chunkX <= playerChunkX + renderDistanceChunks; chunkX++) {
+ for (int chunkZ = playerChunkZ - renderDistanceChunks; chunkZ <= playerChunkZ + renderDistanceChunks; chunkZ++) {
+ String key = String.format("%d,%d", chunkX, chunkZ);
+ if (shouldRecalculate || !chunks.containsKey(key)) {
+ chunks.put(key, new BedrockChunk(chunkX, chunkZ));
+ }
+ BedrockChunk chunk = chunks.get(key);
+ boxes.addAll(chunk.getBlocks());
+ }
+ }
+ return boxes;
+ }
+
+ public boolean shouldRecalculate() {
+ long gameTime = ClientInterop.getGameTime();
+ if (!((Long) gameTime).equals(lastGameTime) && gameTime % 2L == 0L) {
+ lastGameTime = gameTime;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean canProvide(DimensionId dimensionId) {
+ return dimensionId == DimensionId.NETHER && BoundingBoxTypeHelper.shouldRender(BoundingBoxType.BedrockCeiling) && Player.getY() > 110;
+ }
+}
public static final BoundingBoxType Conduit = register("Conduit");
public static final BoundingBoxType SpawnableBlocks = register("Spawnable Blocks");
public static final BoundingBoxType FlowerForest = register("Flower Forest");
+ public static final BoundingBoxType BedrockCeiling = register("Bedrock Ceiling");
public static final BoundingBoxType JungleTemple = register("Jungle_Pyramid");
public static final BoundingBoxType DesertTemple = register("Desert_Pyramid");
}
public static DimensionId OVERWORLD = DimensionId.from(DimensionType.OVERWORLD);
+ public static DimensionId NETHER = DimensionId.from(DimensionType.NETHER);
private final ResourceLocation value;