--- /dev/null
+package com.irtimaled.bbor;
+
+import com.irtimaled.bbor.common.TypeHelper;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.function.Function;
+
+public class ReflectionHelper {
+ public static <T, R> Function<T, R> getPrivateFieldGetter(Class<?> clazz, Type fieldType, Type... genericTypeArguments) {
+ Field field = findField(clazz, fieldType, genericTypeArguments);
+ if (field == null) return obj -> null;
+
+ field.setAccessible(true);
+ return obj -> {
+ try {
+ return (R) field.get(obj);
+ } catch (IllegalAccessException ignored) {
+ return null;
+ }
+ };
+ }
+
+ private static Field findField(Class<?> clazz, Type fieldType, Type[] genericTypeArguments) {
+ for (Field field : clazz.getDeclaredFields()) {
+ Type type = field.getGenericType();
+ ParameterizedType genericType = TypeHelper.as(type, ParameterizedType.class);
+ if (genericType == null) {
+ if (type != fieldType || genericTypeArguments.length > 0) continue;
+ return field;
+ }
+
+ Type rawType = genericType.getRawType();
+ if (rawType != fieldType) continue;
+
+ Type[] actualTypeArguments = genericType.getActualTypeArguments();
+ if (actualTypeArguments.length != genericTypeArguments.length) continue;
+
+ for (int typeIndex = 0; typeIndex < actualTypeArguments.length; typeIndex++) {
+ if (actualTypeArguments[typeIndex] != genericTypeArguments[typeIndex]) return null;
+ }
+
+ return field;
+ }
+ return null;
+ }
+}
package com.irtimaled.bbor.client;
import com.irtimaled.bbor.client.interop.ClientInterop;
+import com.irtimaled.bbor.client.models.BoundingBoxConduit;
import com.irtimaled.bbor.client.providers.*;
import com.irtimaled.bbor.client.renderers.*;
import com.irtimaled.bbor.common.MathHelper;
registerRenderer(BoundingBoxSpawningSphere.class, new SpawningSphereRenderer());
registerRenderer(BoundingBoxBeacon.class, new BeaconRenderer());
registerRenderer(BoundingBoxBiomeBorder.class, new BiomeBorderRenderer());
+ registerRenderer(BoundingBoxConduit.class, new ConduitRenderer());
registerProvider(new SlimeChunkProvider());
registerProvider(new WorldSpawnProvider());
registerProvider(new CustomBeaconProvider());
registerProvider(new BiomeBorderProvider());
registerProvider(new MobSpawnerProvider());
+ registerProvider(new ConduitProvider());
}
public static <T extends AbstractBoundingBox> void registerProvider(IBoundingBoxProvider<T> provider) {
(x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.mobSpawners"), BoundingBoxType.MobSpawner),
(x, width) -> new BoolSettingButton(width, I18n.format("bbor.features.mobSpawners.spawnArea"), ConfigManager.renderMobSpawnerSpawnArea),
(x, width) -> new BoolSettingButton(width, I18n.format("bbor.features.mobSpawners.activationLines"), ConfigManager.renderMobSpawnerActivationLines))
+ .section(I18n.format("bbor.sections.beaconsAndConduits"),
+ (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.beacons"), BoundingBoxType.Beacon),
+ (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.conduits"), BoundingBoxType.Conduit),
+ (x, width) -> new BoolSettingButton(width, I18n.format("bbor.features.conduits.mobHarmArea"), ConfigManager.renderConduitMobHarmArea))
.section(I18n.format("bbor.features.spawningSpheres"),
(x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.spawningSpheres"), BoundingBoxType.AFKSphere),
(x, width) -> new BoolSettingButton(width, I18n.format("bbor.features.spawningSpheres.spawnableBlocks"), ConfigManager.renderAFKSpawnableBlocks),
--- /dev/null
+package com.irtimaled.bbor.client.models;
+
+import com.irtimaled.bbor.common.BoundingBoxType;
+import com.irtimaled.bbor.common.TypeHelper;
+import com.irtimaled.bbor.common.models.BoundingBoxSphere;
+import com.irtimaled.bbor.common.models.Coords;
+
+public class BoundingBoxConduit extends BoundingBoxSphere {
+ private final int level;
+
+ private BoundingBoxConduit(Coords coords, int level, int radius) {
+ super(coords, radius, BoundingBoxType.Conduit);
+ setCenterOffsets(0.5, 0.5, 0.5);
+
+ this.level = level;
+ }
+
+ public static BoundingBoxConduit from(Coords coords, int level) {
+ int radius = 16 * level;
+ return new BoundingBoxConduit(coords, level, radius);
+ }
+
+ @Override
+ public int hashCode() {
+ return TypeHelper.combineHashCodes(getTypeName().hashCode(), getCenter().hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null || getClass() != obj.getClass()) return false;
+ BoundingBoxConduit other = (BoundingBoxConduit) obj;
+ return getCenter().equals(other.getCenter());
+ }
+
+ public int getLevel() {
+ return level;
+ }
+}
--- /dev/null
+package com.irtimaled.bbor.client.providers;
+
+import com.irtimaled.bbor.ReflectionHelper;
+import com.irtimaled.bbor.client.interop.TileEntitiesHelper;
+import com.irtimaled.bbor.client.models.BoundingBoxConduit;
+import com.irtimaled.bbor.common.models.Coords;
+import net.minecraft.tileentity.TileEntityConduit;
+import net.minecraft.util.math.BlockPos;
+
+import java.util.List;
+import java.util.function.Function;
+
+public class ConduitProvider implements IBoundingBoxProvider<BoundingBoxConduit> {
+ private static final Function<TileEntityConduit, List<BlockPos>> blocksFetcher =
+ ReflectionHelper.getPrivateFieldGetter(TileEntityConduit.class, List.class, BlockPos.class);
+
+ @Override
+ public Iterable<BoundingBoxConduit> get(int dimensionId) {
+ return TileEntitiesHelper.map(TileEntityConduit.class, conduit -> {
+ List<BlockPos> blocks = blocksFetcher.apply(conduit);
+ if (blocks == null) return null;
+
+ Coords coords = new Coords(conduit.getPos());
+ return BoundingBoxConduit.from(coords, conduit.isActive() ? blocks.size() / 7 : 0);
+ });
+ }
+}
--- /dev/null
+package com.irtimaled.bbor.client.renderers;
+
+import com.irtimaled.bbor.client.models.BoundingBoxConduit;
+import com.irtimaled.bbor.common.models.Colors;
+import com.irtimaled.bbor.common.models.Coords;
+import com.irtimaled.bbor.config.ConfigManager;
+
+import java.awt.*;
+
+public class ConduitRenderer extends AbstractRenderer<BoundingBoxConduit> {
+ @Override
+ public void render(BoundingBoxConduit boundingBox) {
+ Coords center = boundingBox.getCenter();
+ int level = boundingBox.getLevel();
+ Color color = boundingBox.getColor();
+
+ renderCuboid(new OffsetBox(center, center), color);
+ if (level == 6 && ConfigManager.renderConduitMobHarmArea.get()) {
+ renderCuboid(new OffsetBox(center, center).grow(8, 8, 8), Colors.DARK_ORANGE);
+ }
+ if (level != 0) {
+ OffsetPoint sphereCenter = new OffsetPoint(center)
+ .offset(boundingBox.getCenterOffsetX(), boundingBox.getCenterOffsetY(), boundingBox.getCenterOffsetZ());
+
+ renderSphere(sphereCenter, boundingBox.getRadius() + 0.5, color, 5, 5);
+ }
+ }
+}
public static final BoundingBoxType NetherFossil = register(Color.WHITE, "Nether_Fossil", ConfigManager.drawNetherFossils);
public static final BoundingBoxType BastionRemnant = register(Color.LIGHT_GRAY, "Bastion_Remnant", ConfigManager.drawBastionRemnants);
public static final BoundingBoxType RuinedPortal = register(Colors.COOL_PURPLE, "Ruined_Portal", ConfigManager.drawRuinedPortals);
+ public static final BoundingBoxType Conduit = register(Color.CYAN, "Conduit", ConfigManager.drawConduits);
public static final BoundingBoxType Custom = register(Color.WHITE, "Custom", ConfigManager.drawCustomBoxes);
private static BoundingBoxType register(Color color, String name, Setting<Boolean> shouldRenderSetting) {
return centerOffsetZ;
}
- void setCenterOffsets(double x, double y, double z) {
+ public void setCenterOffsets(double x, double y, double z) {
this.centerOffsetX = x;
this.centerOffsetY = y;
this.centerOffsetZ = z;
public static Setting<Boolean> drawNetherFossils;
public static Setting<Boolean> drawBastionRemnants;
public static Setting<Boolean> drawRuinedPortals;
+ public static Setting<Boolean> drawConduits;
+ public static Setting<Boolean> renderConduitMobHarmArea;
public static void loadConfig(File mcConfigDir) {
configDir = new File(mcConfigDir, "config");
outerBoxesOnly = setup(config, "general", "outerBoxesOnly", false, "If set to true only the outer bounding boxes are rendered.");
alwaysVisible = setup(config, "general", "alwaysVisible", false, "If set to true boxes will be visible even through other blocks.");
keepCacheBetweenSessions = setup(config, "general", "keepCacheBetweenSessions", false, "If set to true bounding box caches will be kept between sessions.");
- drawBeacons = setup(config, "general", "drawBeacons", true, "If set to true beacon bounding boxes will be drawn.");
drawCustomBoxes = setup(config, "general", "drawCustomBoxes", true, "If set to true custom bounding boxes will be drawn.");
+
+ drawBeacons = setup(config, "beacons", "drawBeacons", true, "If set to true beacon bounding boxes will be drawn.");
+
+ drawConduits = setup(config, "conduits", "drawConduits", true, "If set to true conduit bounding spheres will be drawn.");
+ renderConduitMobHarmArea = setup(config, "conduits", "renderConduitMobHarmArea", true, "If set to true a box to show the area where hostile mobs are harmed will be drawn");
+
drawBiomeBorders = setup(config, "biomeBorders", "drawBiomeBorders", true, "If set to true biome borders will be drawn.");
renderOnlyCurrentBiome = setup(config, "biomeBorders", "renderOnlyCurrentBiome", true, "If set to true only the biome border for the current biome will be drawn.");
biomeBordersRenderDistance = setup(config, "biomeBorders", "biomeBordersRenderDistance", 3, "The distance from the player where biome borders will be drawn.");
"bbor.features.spawningSpheres.spawnableBlocks": "Spawnable Blocks",
"bbor.features.biomeBorders": "Biome Borders",
+ "bbor.sections.beaconsAndConduits": "Beacons & Conduits",
+ "bbor.features.beacons": "Beacons",
+ "bbor.features.conduits": "Conduits",
+ "bbor.features.conduits.mobHarmArea": "Mob Harm Area",
+
"bbor.structures.desertTemples": "Desert Temples",
"bbor.structures.jungleTemples": "Jungle Temples",
"bbor.structures.witchHuts": "Witch Huts",