Skip to content

Commit

Permalink
Bump version to 1.0.4
Browse files Browse the repository at this point in the history
- Calculate which boxes to show using the players position and render distance instead of relying on the world.isAreaLoaded function which seems to play up on multiplayer servers
- Set new defaults for Igloos & 1.13 structures
- Update README
  • Loading branch information
irtimaled committed Feb 3, 2019
1 parent bbca873 commit b3c42a8
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 51 deletions.
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# BoundingBoxOutlineReloaded

BoundingBoxOutlineReloaded is a mod for Minecraft Forge, LiteLoader, and Vanilla
BoundingBoxOutlineReloaded is a mod for Minecraft Vanilla, Forge, LiteLoader, Rift and Fabric

# Why did I make it?

Expand All @@ -20,21 +20,27 @@ This mod highlights in a variety of colours and styles the different structures
- Strongholds; yellow boxes show each room in the stronghold. Does anyone make anything with silverfish spawners?
- Woodland Mansions; brown boxes show each room in the woodland mansion. Here's Johnny!
- Mine Shafts; light gray boxes illustrate each of the mine shafts. Cobwebs... grrr!
- Villages; multicoloured spheres encircle the village, with boxes marking if and where iron golems will spawn. You should see the iron titan... CRAZY!
- Villages; multicoloured spheres encircle the village, with boxes marking if and where iron golems will spawn. You should see the iron titan... CRAZY!
- Slime chunks; bright green boxes highlight where slimes will spawn, with a dynamic box that rises to where the players feet are to help find them from the surface. Bouncy... bouncy...
- World Spawn & spawn chunks; red boxes outline the world spawn and the spawn chunks (active & lazy).
- Igloos (*); white boxes show where igloos are. Maybe you can convert the zombie villager back?
- Shipwrecks (*); cyan boxes are like a lighthouse those wary sailors wish they'd had. Time to find some buried treasure?
- Ocean ruins (*); cyan boxes show the different ocean ruin structures. Watch out for those pesky drowns tho!
- Buried treasure (*); cyan boxes highlight where the heart of the sea can be found. Conduit anyone?

(*) Due to how Minecraft generates these structures they will initially float above where they should be, however upon re-logging they should drop down to the correct height. Unfortunately (or fortunately?) buried treasure will always appear at y-90 (unless Mojang change something that is!)

# How it works

As chunks are loaded the game provides metadata about all the different structures & features in those chunks. The mod interprets this meta data, caches the results, and renders the bounding boxes to the screen. In an SMP environment this data is not present on the clients so the mod needs to run on the server where the processing happens and then the relevant metadata is sent to the clients for them to render.

# Installing (Forge/LiteLoader)
# Installing (Forge/LiteLoader/Rift/Fabric)

Make sure you have Forge or LiteLoader installed then drop the mod file into the appropriate mods folder. [Forge Only] If you want to use client/server with your SMP server then make sure the mod is installed on both client and server.
Make sure you have the relevant mod loader installed then drop the mod file into the appropriate mods folder. [Forge Only] If you want to use client/server with your SMP server then make sure the mod is installed on both client and server.

# Installing (Vanilla)

Copy the contents of the Vanilla archive into the JAR file as per usual. In a SMP scenario you'll need to use local dat files - see below.
Double-click the jar file and a profile for the relevant version of Minecraft will be created/updated in the launcher. In a SMP scenario you'll need to use local dat files - see below.

# Configuring

Expand All @@ -53,6 +59,10 @@ End Cities | Both | Process/Render End Cities | drawEndCities | true/false | tru
Strongholds | Both | Process/Render Strongholds | drawStrongholds | true/false | false
Woodland Mansions | Both | Process/Render Mansions | drawMansions | true/false | true
Mine Shafts | Both | Process/Render Mine Shafts | drawMineShafts | true/false | false
Igloos | Client | Process/Render Igloos | drawIgloos | true/false | true
Shipwrecks | Client | Process/Render Shipwrecks | drawShipwrecks | true/false | true
Ocean Ruins | Client | Process/Render Ocean Ruins | drawOceanRuins | true/false | true
Buried Treasure | Client | Process/Render Buried Treasure | drawBuriedTreasure | true/false | true
Villages | Both | Process/Render Villages | drawVillages | true/false | true
Village spheres | Client | Render Villages as spheres instead of cuboids | renderVillageAsSphere | true/false | true
Village Iron Golem Spawn Area | Client | Render Iron Golem Spawn Area within valid Villages | drawIronGolemSpawnArea | true/false | true
Expand All @@ -77,7 +87,7 @@ Open the config/BBOutlineReloaded.cfg file with your text editor of choice and c
Press B, sit back and enjoy the goodness flowing onto your screen.
Press O to switch the "Display Outer Boxes Only" mode on and off, this will allow you to see the full boundary of Nether Fortresses, End Cities, Strongholds and Mineshafts

# Using with vanilla servers
# Bounding boxes when connected to vanilla servers

There are two options when you want bounding boxes to show whilst accessing vanilla servers:-

Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ apply plugin: 'maven-publish'

def mcVersion = '1.13'
group 'com.irtimaled'
version "1.0.4-beta4-$mcVersion"
version "1.0.4-$mcVersion"
archivesBaseName = 'BBOutlineReloaded'

sourceCompatibility = 1.8
Expand Down Expand Up @@ -95,4 +95,4 @@ jar {

artifacts {
archives jar
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,61 @@
import com.irtimaled.bbor.common.models.WorldData;
import com.irtimaled.bbor.config.ConfigManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.dimension.DimensionType;

import java.awt.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

class ClientBoundingBoxProvider {
private static final int CHUNK_SIZE = 16;
private final ClientDimensionCache dimensionCache;

ClientBoundingBoxProvider(ClientDimensionCache dimensionCache) {
this.dimensionCache = dimensionCache;
}

Set<BoundingBox> getBoundingBoxes(DimensionType dimensionType, Boolean outerBoxOnly, WorldClient world) {
private boolean isWithinRenderDistance(BlockPos minBlockPos, BlockPos maxBlockPos) {
int renderDistanceBlocks = Minecraft.getInstance().gameSettings.renderDistanceChunks * CHUNK_SIZE;
int minX = MathHelper.floor(PlayerData.getX() - renderDistanceBlocks);
int maxX = MathHelper.floor(PlayerData.getX() + renderDistanceBlocks);
int minZ = MathHelper.floor(PlayerData.getZ() - renderDistanceBlocks);
int maxZ = MathHelper.floor(PlayerData.getZ() + renderDistanceBlocks);

return maxBlockPos.getX() > minX &&
maxBlockPos.getZ() > minZ &&
minBlockPos.getX() < maxX &&
minBlockPos.getZ() < maxZ;
}

Set<BoundingBox> getBoundingBoxes(DimensionType dimensionType, Boolean outerBoxOnly) {
Set<BoundingBox> boundingBoxes = getClientBoundingBoxes(dimensionType);
BoundingBoxCache boundingBoxCache = dimensionCache.getBoundingBoxes(dimensionType);
if (boundingBoxCache != null) {
if (outerBoxOnly) {
boundingBoxes.addAll(boundingBoxCache.getBoundingBoxes().keySet());
} else {
boundingBoxCache.getBoundingBoxes()
.values()
.forEach(boundingBoxes::addAll);
}
if (boundingBoxCache == null)
return boundingBoxes;

for (Map.Entry<BoundingBox, Set<BoundingBox>> entry : boundingBoxCache.getBoundingBoxes().entrySet()) {
BoundingBox bb = entry.getKey();
if (!isWithinRenderDistance(bb.getMinBlockPos(), bb.getMaxBlockPos())) continue;
if (outerBoxOnly)
boundingBoxes.add(bb);
else
boundingBoxes.addAll(entry.getValue());
}

return boundingBoxes.stream()
.filter(bb -> world.isAreaLoaded(bb.getMinBlockPos(), bb.getMaxBlockPos()))
.collect(Collectors.toSet());

return boundingBoxes;
}

private void addIfWithinRenderDistance(Set<BoundingBox> boundingBoxes, BoundingBox boundingBox)
{
if(isWithinRenderDistance(boundingBox.getMinBlockPos(), boundingBox.getMaxBlockPos()))
boundingBoxes.add(boundingBox);
}

private Set<BoundingBox> getClientBoundingBoxes(DimensionType dimensionType) {
Expand All @@ -50,11 +70,11 @@ private Set<BoundingBox> getClientBoundingBoxes(DimensionType dimensionType) {
Set<BoundingBox> boundingBoxes = new HashSet<>();
if (worldData != null && dimensionType == DimensionType.OVERWORLD) {
if (ConfigManager.drawWorldSpawn.getBoolean()) {
boundingBoxes.add(getWorldSpawnBoundingBox(worldData.getSpawnX(), worldData.getSpawnZ()));
boundingBoxes.add(buildSpawnChunksBoundingBox(worldData.getSpawnX(), worldData.getSpawnZ()));
addIfWithinRenderDistance(boundingBoxes, getSpawnChunksBoundingBox(worldData.getSpawnX(), worldData.getSpawnZ()));
addIfWithinRenderDistance(boundingBoxes, getWorldSpawnBoundingBox(worldData.getSpawnX(), worldData.getSpawnZ()));
}
if (ConfigManager.drawLazySpawnChunks.getBoolean()) {
boundingBoxes.add(getLazySpawnChunksBoundingBox(worldData.getSpawnX(), worldData.getSpawnZ()));
addIfWithinRenderDistance(boundingBoxes, getLazySpawnChunksBoundingBox(worldData.getSpawnX(), worldData.getSpawnZ()));
}
if (ConfigManager.drawSlimeChunks.getBoolean()) {
boundingBoxes.addAll(this.getSlimeChunks());
Expand All @@ -64,21 +84,17 @@ private Set<BoundingBox> getClientBoundingBoxes(DimensionType dimensionType) {
}

private Set<BoundingBoxSlimeChunk> getSlimeChunks() {
Minecraft minecraft = Minecraft.getInstance();
int renderDistanceChunks = minecraft.gameSettings.renderDistanceChunks;
int playerChunkX = MathHelper.floor(minecraft.player.posX / 16.0D);
int playerChunkZ = MathHelper.floor(minecraft.player.posZ / 16.0D);
int renderDistanceChunks = Minecraft.getInstance().gameSettings.renderDistanceChunks;
int playerChunkX = MathHelper.floor(PlayerData.getX() / CHUNK_SIZE);
int playerChunkZ = MathHelper.floor(PlayerData.getZ() / CHUNK_SIZE);
Set<BoundingBoxSlimeChunk> slimeChunks = new HashSet<>();
for (int chunkX = playerChunkX - renderDistanceChunks; chunkX <= playerChunkX + renderDistanceChunks; ++chunkX) {
for (int chunkZ = playerChunkZ - renderDistanceChunks; chunkZ <= playerChunkZ + renderDistanceChunks; ++chunkZ) {
if (isSlimeChunk(chunkX, chunkZ)) {
ChunkPos chunk = new ChunkPos(chunkX, chunkZ);
BlockPos minBlockPos = new BlockPos(chunk.getXStart(), 1, chunk.getZStart());
BlockPos maxBlockPos = new BlockPos(chunk.getXEnd(), 38, chunk.getZEnd());
if (minecraft.world.isAreaLoaded(minBlockPos, maxBlockPos)) {
slimeChunks.add(BoundingBoxSlimeChunk.from(minBlockPos, maxBlockPos, Color.GREEN));
}
}
if (!isSlimeChunk(chunkX, chunkZ)) continue;
ChunkPos chunk = new ChunkPos(chunkX, chunkZ);
BlockPos minBlockPos = new BlockPos(chunk.getXStart(), 1, chunk.getZStart());
BlockPos maxBlockPos = new BlockPos(chunk.getXEnd(), 38, chunk.getZEnd());
slimeChunks.add(BoundingBoxSlimeChunk.from(minBlockPos, maxBlockPos, Color.GREEN));
}
}
return slimeChunks;
Expand All @@ -94,7 +110,7 @@ private boolean isSlimeChunk(int chunkX, int chunkZ) {
return r.nextInt(10) == 0;
}

private BoundingBox buildSpawnChunksBoundingBox(int spawnX, int spawnZ) {
private BoundingBox getSpawnChunksBoundingBox(int spawnX, int spawnZ) {
return dimensionCache.getOrSetSpawnChunks(() -> buildSpawnChunksBoundingBox(spawnX, spawnZ, 12));
}

Expand All @@ -103,14 +119,13 @@ private BoundingBox getLazySpawnChunksBoundingBox(int spawnX, int spawnZ) {
}

private BoundingBox buildSpawnChunksBoundingBox(int spawnX, int spawnZ, int size) {
double chunkSize = 16;
double midOffset = chunkSize * (size / 2);
double midX = Math.round((float) (spawnX / chunkSize)) * chunkSize;
double midZ = Math.round((float) (spawnZ / chunkSize)) * chunkSize;
double midOffset = CHUNK_SIZE * (size / 2.0);
double midX = Math.round((float) (spawnX / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
double midZ = Math.round((float) (spawnZ / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
BlockPos minBlockPos = new BlockPos(midX - midOffset, 0, midZ - midOffset);
if (spawnX / chunkSize % 0.5D == 0.0D && spawnZ / chunkSize % 0.5D == 0.0D) {
midX += chunkSize;
midZ += chunkSize;
if (spawnX / (double) CHUNK_SIZE % 0.5D == 0.0D && spawnZ / (double) CHUNK_SIZE % 0.5D == 0.0D) {
midX += (double) CHUNK_SIZE;
midZ += (double) CHUNK_SIZE;
}
BlockPos maxBlockPos = new BlockPos(midX + midOffset, 0, midZ + midOffset);
return BoundingBoxWorldSpawn.from(minBlockPos, maxBlockPos, Color.RED);
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/com/irtimaled/bbor/client/ClientRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.irtimaled.bbor.client.renderers.*;
import com.irtimaled.bbor.common.models.*;
import com.irtimaled.bbor.config.ConfigManager;
import net.minecraft.client.Minecraft;
import net.minecraft.world.dimension.DimensionType;
import org.lwjgl.opengl.GL11;

Expand All @@ -24,7 +23,7 @@ public class ClientRenderer {
}

public void render(DimensionType dimensionType, Boolean outerBoxesOnly) {
Set<BoundingBox> boundingBoxes = clientBoundingBoxProvider.getBoundingBoxes(dimensionType, outerBoxesOnly, Minecraft.getInstance().world);
Set<BoundingBox> boundingBoxes = clientBoundingBoxProvider.getBoundingBoxes(dimensionType, outerBoxesOnly);
if (boundingBoxes == null || boundingBoxes.size() == 0)
return;

Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/irtimaled/bbor/config/ConfigManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ public static void loadConfig(File mcConfigDir) {
drawLazySpawnChunks = SetupBooleanProperty(config, "features", "drawLazySpawnChunks", false, "If set to true the lazy spawn chunks bounding boxes will be drawn. (default: false)");
drawEndCities = SetupBooleanProperty(config, "features", "drawEndCities", true, "If set to true end city bounding boxes will be drawn. (default: true)");
drawMansions = SetupBooleanProperty(config, "features", "drawMansions", true, "If set to true woodland mansions will be drawn. (default: true)");
drawShipwrecks = SetupBooleanProperty(config, "features", "drawShipwrecks", false, "If set to true shipwrecks will be drawn. (default: false)");
drawOceanRuins = SetupBooleanProperty(config, "features", "drawOceanRuins", false, "If set to true ocean ruins will be drawn. (default: false)");
drawBuriedTreasure = SetupBooleanProperty(config, "features", "drawBuriedTreasures", false, "If set to true buried treasure will be drawn. (default: false)");
drawIgloos = SetupBooleanProperty(config, "features", "drawIgloos", false, "If set to true igloos will be drawn. (default: false)");
drawIgloos = SetupBooleanProperty(config, "features", "drawIgloos", true, "If set to true igloos will be drawn. (default: true)");
drawShipwrecks = SetupBooleanProperty(config, "features", "drawShipwrecks", true, "If set to true shipwrecks will be drawn. (default: true)");
drawOceanRuins = SetupBooleanProperty(config, "features", "drawOceanRuins", true, "If set to true ocean ruins will be drawn. (default: true)");
drawBuriedTreasure = SetupBooleanProperty(config, "features", "drawBuriedTreasures", true, "If set to true buried treasure will be drawn. (default: true)");
config.save();
}

Expand Down

0 comments on commit b3c42a8

Please sign in to comment.