}
public static void render(float partialTicks) {
+ proxy.tick();
proxy.render(partialTicks);
}
import com.irtimaled.bbor.Logger;
import com.irtimaled.bbor.common.BoundingBoxCache;
import com.irtimaled.bbor.common.CommonProxy;
+import com.irtimaled.bbor.common.VillageColorCache;
+import com.irtimaled.bbor.common.VillageProcessor;
import com.irtimaled.bbor.common.StructureType;
import com.irtimaled.bbor.common.models.*;
import com.irtimaled.bbor.config.ConfigManager;
int radius = village.getInteger("Radius");
int population = village.getInteger("PopSize");
Set<BlockPos> doors = getDoors(village);
- BoundingBox boundingBox = BoundingBoxVillage.from(center, radius, population, doors);
+ BoundingBox boundingBox = BoundingBoxVillage.from(center, radius, village.hashCode(), population, doors);
cache.addBoundingBox(boundingBox);
}
worldSpawnBoundingBox = null;
spawnChunksBoundingBox = null;
lazySpawnChunksBoundingBox = null;
+ VillageColorCache.clear();
dimensionCache.clear();
+ villageProcessors.forEach(VillageProcessor::clear);
}
private void renderBoundingBoxes(Map<BoundingBox, Set<BoundingBox>> map, Set<BoundingBox> clientBoundingBoxes) {
import com.irtimaled.bbor.Logger;
import com.irtimaled.bbor.ReflectionHelper;
+import com.irtimaled.bbor.config.ConfigManager;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.ChunkProviderServer;
import net.minecraft.world.gen.IChunkGenerator;
+import java.util.HashSet;
+import java.util.Set;
+
public class CommonProxy {
protected DimensionCache dimensionCache = new DimensionCache();
+ protected Set<VillageProcessor> villageProcessors = new HashSet<>();
private IVillageEventHandler eventHandler = null;
dimensionCache.setWorldData(world.getSeed(), world.getWorldInfo().getSpawnX(), world.getWorldInfo().getSpawnZ());
DimensionType dimensionType = world.provider.getDimensionType();
Logger.info("create world dimension: %s, %s (chunkprovider: %s) (seed: %d)", dimensionType, world.getClass().toString(), chunkGenerator.getClass().toString(), world.getSeed());
- DimensionProcessor boundingBoxCache = new DimensionProcessor(eventHandler, world, dimensionType, chunkGenerator);
+ DimensionProcessor boundingBoxCache = new DimensionProcessor(dimensionType, chunkGenerator);
dimensionCache.put(dimensionType, boundingBoxCache);
+ if (ConfigManager.drawVillages.getBoolean()) {
+ villageProcessors.add(new VillageProcessor(world, dimensionType, eventHandler, boundingBoxCache));
+ }
}
}
dimensionCache.refresh(dimensionType);
}
+ public void tick() {
+ villageProcessors.forEach(VillageProcessor::process);
+ }
+
public void init() {
}
import com.irtimaled.bbor.ReflectionHelper;
import com.irtimaled.bbor.common.models.BoundingBox;
import com.irtimaled.bbor.common.models.BoundingBoxStructure;
-import com.irtimaled.bbor.common.models.BoundingBoxVillage;
import com.irtimaled.bbor.config.ConfigManager;
-import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
-import net.minecraft.village.Village;
-import net.minecraft.village.VillageDoorInfo;
import net.minecraft.world.DimensionType;
-import net.minecraft.world.World;
import net.minecraft.world.gen.ChunkGeneratorEnd;
import net.minecraft.world.gen.ChunkGeneratorHell;
import net.minecraft.world.gen.ChunkGeneratorOverworld;
import java.awt.*;
import java.util.*;
-import java.util.List;
public class DimensionProcessor extends BoundingBoxCache {
- private World world;
- private IVillageEventHandler eventHandler;
-
- DimensionProcessor(IVillageEventHandler eventHandler, World world, DimensionType dimensionType, IChunkGenerator chunkGenerator) {
- this.eventHandler = eventHandler;
- this.world = world;
+ DimensionProcessor(DimensionType dimensionType, IChunkGenerator chunkGenerator) {
this.dimensionType = dimensionType;
this.chunkGenerator = chunkGenerator;
- villageCache = new HashMap<>();
- slimeChunkCache = new HashSet<>();
- worldSpawnCache = new HashSet<>();
}
private DimensionType dimensionType;
private IChunkGenerator chunkGenerator;
- private Map<Integer, BoundingBoxVillage> villageCache;
- private Set<BoundingBox> slimeChunkCache;
- private Set<BoundingBox> worldSpawnCache;
private boolean closed = false;
public void close() {
closed = true;
chunkGenerator = null;
- villageCache.clear();
- slimeChunkCache.clear();
- worldSpawnCache.clear();
super.close();
}
structureBoundingBoxes.add(BoundingBoxStructure.from(structureComponent.getBoundingBox(), color));
}
addBoundingBoxes(boundingBox, structureBoundingBoxes);
- Logger.info("[%s] new boundingBoxCacheMap entries: %d", dimensionType, structureBoundingBoxes.size());
- }
- }
- }
- }
-
- if (ConfigManager.drawVillages.getBoolean() &&
- world.getVillageCollection() != null) {
- Map<Integer, BoundingBoxVillage> villageBoundingBoxes = new HashMap<>();
- List<Village> villages = world.getVillageCollection().getVillageList();
- for (Village village : villages) {
- int villageId = village.hashCode();
- BlockPos center = village.getCenter();
- Color color = null;
- if (villageCache.containsKey(villageId)) {
- BoundingBoxVillage boundingBoxVillage = villageCache.get(villageId);
- if (boundingBoxVillage.getCenter() == center) {
- villageBoundingBoxes.put(villageId, boundingBoxVillage);
- villageCache.remove(villageId);
- continue;
+ Logger.info("[%s] new dimensionCache entries: %d", dimensionType, structureBoundingBoxes.size());
}
- color = boundingBoxVillage.getColor();
}
-
- Integer radius = village.getVillageRadius();
- int population = village.getNumVillagers();
- Set<BlockPos> doors = getDoorsFromVillage(village);
- villageBoundingBoxes.put(villageId, BoundingBoxVillage.from(center, radius, color, population, doors));
}
- processDelta(villageCache, villageBoundingBoxes);
- villageCache = villageBoundingBoxes;
- }
- }
-
- private Set<BlockPos> getDoorsFromVillage(Village village) {
- Set<BlockPos> doors = new HashSet<>();
- for (Object doorInfo : village.getVillageDoorInfoList()) {
- VillageDoorInfo villageDoorInfo = (VillageDoorInfo) doorInfo;
- doors.add(villageDoorInfo.getDoorBlockPos());
- }
- return doors;
- }
-
- private void processDelta(Map<Integer, BoundingBoxVillage> oldVillages, Map<Integer, BoundingBoxVillage> newVillages) {
- for (BoundingBox village : oldVillages.values()) {
- removeBoundingBox(village);
- if (eventHandler != null) {
- eventHandler.villageRemoved(this.dimensionType, village);
- }
- }
- for (BoundingBox village : newVillages.values()) {
- if (!isCached(village))
- addBoundingBox(village);
}
}
}
--- /dev/null
+package com.irtimaled.bbor.common;
+
+import java.awt.*;
+import java.util.HashMap;
+import java.util.Map;
+
+public class VillageColorCache {
+ private static int colorIndex = -1;
+
+ public static void clear() {
+ colorIndex = -1;
+ villageColorCache.clear();
+ }
+
+ private static Color getNextColor() {
+ ++colorIndex;
+ switch (colorIndex % 6) {
+ case 0:
+ return Color.RED;
+ case 1:
+ return Color.GREEN;
+ case 2:
+ return Color.BLUE;
+ case 3:
+ return Color.MAGENTA;
+ case 4:
+ return Color.YELLOW;
+ case 5:
+ return Color.CYAN;
+ }
+ return Color.WHITE;
+ }
+
+ private static Map<Integer, Color> villageColorCache = new HashMap<>();
+
+ public static Color getColor(int villageId) {
+ return villageColorCache.computeIfAbsent(villageId, k -> getNextColor());
+ }
+}
--- /dev/null
+package com.irtimaled.bbor.common;
+
+import com.irtimaled.bbor.common.models.BoundingBoxVillage;
+import net.minecraft.village.Village;
+import net.minecraft.village.VillageCollection;
+import net.minecraft.world.DimensionType;
+import net.minecraft.world.World;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class VillageProcessor {
+ private final World world;
+ private final DimensionType dimensionType;
+ private final IVillageEventHandler eventHandler;
+ private BoundingBoxCache boundingBoxCache;
+ private Map<Integer, BoundingBoxVillage> villageCache = new HashMap<>();
+
+ VillageProcessor(World world, DimensionType dimensionType, IVillageEventHandler eventHandler, BoundingBoxCache boundingBoxCache) {
+ this.world = world;
+ this.dimensionType = dimensionType;
+ this.eventHandler = eventHandler;
+ this.boundingBoxCache = boundingBoxCache;
+ }
+
+ synchronized void process() {
+ Map<Integer, BoundingBoxVillage> oldVillages = new HashMap<>(villageCache);
+ Map<Integer, BoundingBoxVillage> newVillages = new HashMap<>();
+ VillageCollection villageCollection = world.getVillageCollection();
+ if (villageCollection != null) {
+ List<Village> villages = villageCollection.getVillageList();
+ for (Village village : villages) {
+ int villageId = village.hashCode();
+ BoundingBoxVillage newVillage = oldVillages.get(villageId);
+ if (newVillage != null && newVillage.matches(village)) {
+ oldVillages.remove(villageId);
+ } else {
+ newVillage = BoundingBoxVillage.from(village);
+ }
+ newVillages.put(villageId, newVillage);
+ }
+
+ }
+ for (BoundingBoxVillage village : oldVillages.values()) {
+ boundingBoxCache.removeBoundingBox(village);
+ if (eventHandler != null) {
+ eventHandler.villageRemoved(dimensionType, village);
+ }
+ }
+ for (BoundingBoxVillage village : newVillages.values()) {
+ boundingBoxCache.addBoundingBox(village);
+ }
+ villageCache = newVillages;
+ }
+
+ public void clear() {
+ villageCache.clear();
+ }
+}
package com.irtimaled.bbor.common.models;
+import com.irtimaled.bbor.common.VillageColorCache;
import net.minecraft.util.math.BlockPos;
+import net.minecraft.village.Village;
+import net.minecraft.village.VillageDoorInfo;
import java.awt.*;
+import java.util.HashSet;
import java.util.Set;
public class BoundingBoxVillage extends BoundingBox {
private Set<BlockPos> doors;
private Double centerOffsetX;
private Double centerOffsetZ;
+ private int villageHash;
- protected BoundingBoxVillage(BlockPos center, Integer radius, Color color, boolean spawnsIronGolems, Set<BlockPos> doors, BlockPos minBlockPos, BlockPos maxBlockPos) {
+ private BoundingBoxVillage(BlockPos center, Integer radius, Color color, boolean spawnsIronGolems, Set<BlockPos> doors, BlockPos minBlockPos, BlockPos maxBlockPos) {
super(minBlockPos, maxBlockPos, color);
this.center = center;
this.radius = radius;
this.spawnsIronGolems = spawnsIronGolems;
this.doors = doors;
+ this.villageHash = computeHash(center, radius, spawnsIronGolems, doors);
calculateCenterOffsets(doors);
}
- public static BoundingBoxVillage from(BlockPos center, Integer radius, int population, Set<BlockPos> doors) {
- return from(center, radius, null, population, doors);
- }
-
- public static BoundingBoxVillage from(BlockPos center, Integer radius, Color color, int population, Set<BlockPos> doors) {
- Boolean spawnsIronGolems = population >= 10 && doors.size() >= 21;
- return from(center, radius, color, spawnsIronGolems, doors);
- }
-
public static BoundingBoxVillage from(BlockPos center, Integer radius, Color color, boolean spawnsIronGolems, Set<BlockPos> doors) {
BlockPos minBlockPos = new BlockPos(center.getX() - radius,
center.getY() - 4,
BlockPos maxBlockPos = new BlockPos(center.getX() + radius,
center.getY() + 4,
center.getZ() + radius);
- if (color == null)
- color = getNextColor();
return new BoundingBoxVillage(center, radius, color, spawnsIronGolems, doors, minBlockPos, maxBlockPos);
}
+ public static BoundingBoxVillage from(BlockPos center, Integer radius, int villageId, int population, Set<BlockPos> doors) {
+ Boolean spawnsIronGolems = shouldSpawnIronGolems(population, doors.size());
+ Color color = VillageColorCache.getColor(villageId);
+ return from(center, radius, color, spawnsIronGolems, doors);
+ }
+
+ private static boolean shouldSpawnIronGolems(int population, int doorCount) {
+ return population >= 10 && doorCount >= 21;
+ }
+
+ public static BoundingBoxVillage from(Village village) {
+ BlockPos center = village.getCenter();
+ int radius = village.getVillageRadius();
+ Set<BlockPos> doors = getDoorsFromVillage(village);
+ return from(center, radius, village.hashCode(), village.getNumVillagers(), doors);
+ }
+
+ private static Set<BlockPos> getDoorsFromVillage(Village village) {
+ Set<BlockPos> doors = new HashSet<>();
+ for (Object doorInfo : village.getVillageDoorInfoList()) {
+ VillageDoorInfo villageDoorInfo = (VillageDoorInfo) doorInfo;
+ doors.add(villageDoorInfo.getDoorBlockPos());
+ }
+ return doors;
+ }
+
private void calculateCenterOffsets(Set<BlockPos> doors) {
boolean processedFirstDoor = false;
int minX = 0;
return centerOffsetZ;
}
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
+ private static int computeHash(BlockPos center, Integer radius, boolean spawnsIronGolems, Set<BlockPos> doors) {
+ int result = (center.hashCode() * 31) + radius;
for (BlockPos door : doors) {
- result = prime * result + door.hashCode();
+ result = (31 * result) + door.hashCode();
+ }
+ if (spawnsIronGolems) {
+ result = 31 * result;
}
return result;
}
- public boolean getSpawnsIronGolems() {
- return spawnsIronGolems;
+ public boolean matches(Village village) {
+ return this.villageHash == computeHash(village.getCenter(),
+ village.getVillageRadius(),
+ shouldSpawnIronGolems(village.getNumVillagers(), village.getNumVillageDoors()),
+ getDoorsFromVillage(village));
}
- private static int colorIndex = -1;
-
- public static Color getNextColor() {
- ++colorIndex;
- switch (colorIndex % 6) {
- case 0:
- return Color.RED;
- case 1:
- return Color.GREEN;
- case 2:
- return Color.BLUE;
- case 3:
- return Color.MAGENTA;
- case 4:
- return Color.YELLOW;
- case 5:
- return Color.CYAN;
- }
- return Color.WHITE;
+ @Override
+ public int hashCode() {
+ return (super.hashCode() * 31) + villageHash;
+ }
+
+ public boolean getSpawnsIronGolems() {
+ return spawnsIronGolems;
}
public Set<BlockPos> getDoors() {
sendToPlayer(player, getDimensionCache().getBoundingBoxes(dimensionType));
}
}
+ getProxy().tick();
}
private void sendToPlayer(EntityPlayerMP player, BoundingBoxCache boundingBoxCache) {