1 package com.irtimaled.bbor.common.models;
3 import com.irtimaled.bbor.common.BoundingBoxType;
4 import com.irtimaled.bbor.common.VillageColorCache;
5 import net.minecraft.util.math.BlockPos;
6 import net.minecraft.village.Village;
7 import net.minecraft.village.VillageDoorInfo;
10 import java.util.HashSet;
11 import java.util.List;
14 public class BoundingBoxVillage extends BoundingBox {
15 private final BlockPos center;
16 private final Integer radius;
17 private final boolean spawnsIronGolems;
18 private final Color color;
19 private Set<BlockPos> doors;
20 private Double centerOffsetX;
21 private Double centerOffsetZ;
22 private int villageHash;
24 private BoundingBoxVillage(BlockPos center, Integer radius, Color color, boolean spawnsIronGolems, Set<BlockPos> doors, BlockPos minBlockPos, BlockPos maxBlockPos) {
25 super(minBlockPos, maxBlockPos, BoundingBoxType.Village);
29 this.spawnsIronGolems = spawnsIronGolems;
31 this.villageHash = computeHash(center, radius, spawnsIronGolems, doors);
32 calculateCenterOffsets(doors);
35 public static BoundingBoxVillage from(BlockPos center, Integer radius, Color color, boolean spawnsIronGolems, Set<BlockPos> doors) {
36 BlockPos minBlockPos = new BlockPos(center.getX() - radius,
38 center.getZ() - radius);
39 BlockPos maxBlockPos = new BlockPos(center.getX() + radius,
41 center.getZ() + radius);
42 return new BoundingBoxVillage(center, radius, color, spawnsIronGolems, doors, minBlockPos, maxBlockPos);
45 public static BoundingBoxVillage from(BlockPos center, Integer radius, int villageId, int population, Set<BlockPos> doors) {
46 Boolean spawnsIronGolems = shouldSpawnIronGolems(population, doors.size());
47 Color color = VillageColorCache.getColor(villageId);
48 return from(center, radius, color, spawnsIronGolems, doors);
51 private static boolean shouldSpawnIronGolems(int population, int doorCount) {
52 return population >= 10 && doorCount >= 21;
55 public static BoundingBoxVillage from(Village village) {
56 BlockPos center = village.getCenter();
57 int radius = village.getVillageRadius();
58 Set<BlockPos> doors = getDoorsFromVillage(village);
59 return from(center, radius, village.hashCode(), village.getNumVillagers(), doors);
62 private static Set<BlockPos> getDoorsFromVillage(Village village) {
63 Set<BlockPos> doors = new HashSet<>();
64 List<VillageDoorInfo> doorInfoList = village.getVillageDoorInfoList();
65 for (int i = 0; i < doorInfoList.size(); i++) {
66 VillageDoorInfo doorInfo = doorInfoList.get(i);
67 doors.add(doorInfo.getDoorBlockPos());
72 private void calculateCenterOffsets(Set<BlockPos> doors) {
73 boolean processedFirstDoor = false;
78 for (BlockPos door : doors) {
79 if (!processedFirstDoor ||
82 if (!processedFirstDoor ||
85 if (!processedFirstDoor ||
88 if (!processedFirstDoor ||
92 processedFirstDoor = true;
94 centerOffsetX = Math.abs(maxX - minX) % 2 == 0 ? 0.5 : (minX < 0 ? 0 : 1);
95 centerOffsetZ = Math.abs(maxZ - minZ) % 2 == 0 ? 0.5 : (minZ < 0 ? 0 : 1);
99 public String toString() {
100 return "(" + center.toString() + "; " + radius.toString() + ")";
103 public Integer getRadius() {
107 public BlockPos getCenter() {
111 public Color getColor() { return color; }
113 public Double getCenterOffsetX() {
114 return centerOffsetX;
117 public Double getCenterOffsetZ() {
118 return centerOffsetZ;
121 private static int computeHash(BlockPos center, Integer radius, boolean spawnsIronGolems, Set<BlockPos> doors) {
122 int result = (center.hashCode() * 31) + radius;
123 for (BlockPos door : doors) {
124 result = (31 * result) + door.hashCode();
126 if (spawnsIronGolems) {
127 result = 31 * result;
132 public boolean matches(Village village) {
133 return this.villageHash == computeHash(village.getCenter(),
134 village.getVillageRadius(),
135 shouldSpawnIronGolems(village.getNumVillagers(), village.getNumVillageDoors()),
136 getDoorsFromVillage(village));
140 public int hashCode() {
141 return (super.hashCode() * 31) + villageHash;
144 public boolean getSpawnsIronGolems() {
145 return spawnsIronGolems;
148 public Set<BlockPos> getDoors() {