]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/commitdiff
Add support for custom line
authorIrtimaled <irtimaled@gmail.com>
Thu, 14 May 2020 03:44:06 +0000 (20:44 -0700)
committerIrtimaled <irtimaled@gmail.com>
Mon, 18 May 2020 00:31:27 +0000 (17:31 -0700)
src/main/java/com/irtimaled/bbor/client/ClientRenderer.java
src/main/java/com/irtimaled/bbor/client/commands/CustomCommand.java
src/main/java/com/irtimaled/bbor/client/commands/LineCommandBuilder.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/models/BoundingBoxLine.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/providers/CustomLineProvider.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/renderers/LineRenderer.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/renderers/Renderer.java
src/main/resources/assets/bbor/lang/en_us.json

index 6dedcf31da5e2a0c4e44484e73d771bff2089ee1..2bf9a962e648117fde9fd6bd2a9aac604f5aeb94 100644 (file)
@@ -49,6 +49,7 @@ public class ClientRenderer {
         registerRenderer(BoundingBoxBiomeBorder.class, new BiomeBorderRenderer());
         registerRenderer(BoundingBoxConduit.class, new ConduitRenderer());
         registerRenderer(BoundingBoxSpawnableBlocks.class, new SpawnableBlocksRenderer());
+        registerRenderer(BoundingBoxLine.class, new LineRenderer());
 
         registerProvider(new SlimeChunkProvider());
         registerProvider(new WorldSpawnProvider());
@@ -60,6 +61,7 @@ public class ClientRenderer {
         registerProvider(new MobSpawnerProvider());
         registerProvider(new ConduitProvider());
         registerProvider(new SpawnableBlocksProvider());
+        registerProvider(new CustomLineProvider());
     }
 
     public static <T extends AbstractBoundingBox> void registerProvider(IBoundingBoxProvider<T> provider) {
index 184a860ffae10659f718a090726a69472a99702e..2cd9af9c5c904a7f4b37e7264d69cca256b9e03f 100644 (file)
@@ -2,6 +2,7 @@ package com.irtimaled.bbor.client.commands;
 
 import com.irtimaled.bbor.client.providers.CustomBeaconProvider;
 import com.irtimaled.bbor.client.providers.CustomBoxProvider;
+import com.irtimaled.bbor.client.providers.CustomLineProvider;
 import com.mojang.brigadier.CommandDispatcher;
 import com.mojang.brigadier.builder.LiteralArgumentBuilder;
 import net.minecraft.command.Commands;
@@ -11,15 +12,18 @@ public class CustomCommand {
     private static final String COMMAND = "bbor:custom";
     private static final String BOX = "box";
     private static final String BEACON = "beacon";
+    private static final String LINE = "line";
 
     public static void register(CommandDispatcher<ISuggestionProvider> commandDispatcher) {
         LiteralArgumentBuilder command = Commands.literal(COMMAND)
                 .then(BoxCommandBuilder.build(BOX))
                 .then(BeaconCommandBuilder.build(BEACON))
+                .then(LineCommandBuilder.build(LINE))
                 .then(Commands.literal(ArgumentNames.CLEAR)
                         .executes(context -> {
                             CustomBoxProvider.clear();
                             CustomBeaconProvider.clear();
+                            CustomLineProvider.clear();
 
                             CommandHelper.feedback(context, "bbor.commands.custom.cleared.all");
                             return 0;
diff --git a/src/main/java/com/irtimaled/bbor/client/commands/LineCommandBuilder.java b/src/main/java/com/irtimaled/bbor/client/commands/LineCommandBuilder.java
new file mode 100644 (file)
index 0000000..048b2aa
--- /dev/null
@@ -0,0 +1,55 @@
+package com.irtimaled.bbor.client.commands;
+
+import com.irtimaled.bbor.client.providers.CustomLineProvider;
+import com.irtimaled.bbor.common.models.Point;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.context.CommandContext;
+import com.mojang.brigadier.exceptions.CommandSyntaxException;
+import net.minecraft.command.CommandSource;
+import net.minecraft.command.Commands;
+
+class LineCommandBuilder {
+    private static final String WIDTH = "width";
+
+    static LiteralArgumentBuilder<CommandSource> build(String command) {
+        return Commands.literal(command)
+                .then(Commands.literal(ArgumentNames.ADD)
+                        .then(Commands.argument(ArgumentNames.FROM, Arguments.point())
+                                .then(Commands.argument(ArgumentNames.TO, Arguments.point())
+                                        .executes(LineCommandBuilder::addLine)
+                                        .then(Commands.argument(WIDTH, Arguments.doubleArg())
+                                                .executes(LineCommandBuilder::addLine)))))
+                .then(Commands.literal(ArgumentNames.CLEAR)
+                        .executes(context -> {
+                            CustomLineProvider.clear();
+
+                            CommandHelper.feedback(context, "bbor.commands.line.cleared.all");
+                            return 0;
+                        })
+                        .then(Commands.argument(ArgumentNames.FROM, Arguments.coords())
+                                .then(Commands.argument(ArgumentNames.TO, Arguments.coords())
+                                        .executes(context -> {
+                                            Point from = Arguments.getPoint(context, ArgumentNames.FROM).snapXZ(0.5d);
+                                            Point to = Arguments.getPoint(context, ArgumentNames.TO).snapXZ(0.5d);
+                                            boolean removed = CustomLineProvider.remove(from, to);
+
+                                            String format = removed ? "bbor.commands.line.cleared" : "bbor.commands.line.notFound";
+                                            CommandHelper.feedback(context, format,
+                                                    from.getX(), from.getY(), from.getZ(),
+                                                    to.getX(), to.getY(), to.getZ());
+                                            return 0;
+                                        }))));
+    }
+
+    private static int addLine(CommandContext<CommandSource> context) throws CommandSyntaxException {
+        Point from = Arguments.getPoint(context, ArgumentNames.FROM).snapXZ(0.5d);
+        Point to = Arguments.getPoint(context, ArgumentNames.TO).snapXZ(0.5d);
+        Double width = Arguments.getDouble(context, WIDTH);
+        CustomLineProvider.add(from, to, width);
+
+        CommandHelper.feedback(context, "bbor.commands.line.added",
+                from.getX(), from.getY(), from.getZ(),
+                to.getX(), to.getY(), to.getZ());
+        return 0;
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxLine.java b/src/main/java/com/irtimaled/bbor/client/models/BoundingBoxLine.java
new file mode 100644 (file)
index 0000000..b8b02bd
--- /dev/null
@@ -0,0 +1,96 @@
+package com.irtimaled.bbor.client.models;
+
+import com.irtimaled.bbor.common.BoundingBoxType;
+import com.irtimaled.bbor.common.TypeHelper;
+import com.irtimaled.bbor.common.models.AbstractBoundingBox;
+import com.irtimaled.bbor.common.models.Point;
+
+public class BoundingBoxLine extends AbstractBoundingBox {
+    private final Point minPoint;
+    private final Point maxPoint;
+    private final Double width;
+    private final Point[] corners;
+
+    protected BoundingBoxLine(Point minPoint, Point maxPoint, double width, BoundingBoxType type, Point... corners) {
+        super(type);
+        this.minPoint = minPoint;
+        this.maxPoint = maxPoint;
+        this.width = width;
+        this.corners = corners;
+    }
+
+    public static BoundingBoxLine from(Point minPoint, Point maxPoint, Double width, BoundingBoxType type) {
+        if (width == 0) return new BoundingBoxLine(minPoint, maxPoint, width, type);
+
+        double halfWidth = width / 2.0d;
+
+        double dx = maxPoint.getX() - minPoint.getX();
+        double dz = maxPoint.getZ() - minPoint.getZ();
+
+        double dxm = dx == 0 ? 0 : dx / Math.abs(dx);
+        double dzm = dz == 0 ? 0 : dz / Math.abs(dz);
+
+        double xc, zc;
+        if (dxm == 0 || dzm == 0) {
+            xc = Math.abs(dzm) * halfWidth;
+            zc = Math.abs(dxm) * halfWidth;
+        } else {
+            double h = Math.sqrt(dx * dx + dz * dz);
+            double theta = Math.acos((dz * dz + h * h - dx * dx) / (2 * dz * h));
+            zc = halfWidth * Math.sin(theta);
+            xc = Math.sqrt(halfWidth * halfWidth - zc * zc) * dxm * dzm;
+        }
+
+        return new BoundingBoxLine(minPoint, maxPoint, width, type,
+                new Point(minPoint.getX() + xc, minPoint.getY(), minPoint.getZ() - zc),
+                new Point(minPoint.getX() - xc, minPoint.getY(), minPoint.getZ() + zc),
+                new Point(maxPoint.getX() - xc, maxPoint.getY(), maxPoint.getZ() + zc),
+                new Point(maxPoint.getX() + xc, maxPoint.getY(), maxPoint.getZ() - zc));
+    }
+
+    @Override
+    public int hashCode() {
+        return TypeHelper.combineHashCodes(minPoint.hashCode(), maxPoint.hashCode());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null || getClass() != obj.getClass()) return false;
+        BoundingBoxLine other = (BoundingBoxLine) obj;
+        return minPoint.equals(other.minPoint) && maxPoint.equals(other.maxPoint);
+    }
+
+    public Point getMinPoint() {
+        return minPoint;
+    }
+
+    public Point getMaxPoint() {
+        return maxPoint;
+    }
+
+    public double getWidth() {
+        return width;
+    }
+
+    public Point[] getCorners() {
+        return corners;
+    }
+
+    @Override
+    public Boolean intersectsBounds(int minX, int minZ, int maxX, int maxZ) {
+        boolean minXWithinBounds = isBetween(minPoint.getX(), minX, maxX);
+        boolean maxXWithinBounds = isBetween(maxPoint.getX(), minX, maxX);
+        boolean minZWithinBounds = isBetween(minPoint.getZ(), minZ, maxZ);
+        boolean maxZWithinBounds = isBetween(maxPoint.getZ(), minZ, maxZ);
+
+        return (minXWithinBounds && minZWithinBounds) ||
+                (maxXWithinBounds && maxZWithinBounds) ||
+                (minXWithinBounds && maxZWithinBounds) ||
+                (maxXWithinBounds && minZWithinBounds);
+    }
+
+    private boolean isBetween(double val, int min, int max) {
+        return val >= min && val <= max;
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/client/providers/CustomLineProvider.java b/src/main/java/com/irtimaled/bbor/client/providers/CustomLineProvider.java
new file mode 100644 (file)
index 0000000..6c50944
--- /dev/null
@@ -0,0 +1,43 @@
+package com.irtimaled.bbor.client.providers;
+
+import com.irtimaled.bbor.client.Player;
+import com.irtimaled.bbor.client.models.BoundingBoxLine;
+import com.irtimaled.bbor.common.BoundingBoxType;
+import com.irtimaled.bbor.common.models.Point;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class CustomLineProvider implements IBoundingBoxProvider<BoundingBoxLine> {
+    private static final Map<Integer, Map<Integer, BoundingBoxLine>> dimensionCache = new HashMap<>();
+
+    private static int getHashKey(Point minPoint, Point maxPoint) {
+        return (31 + minPoint.hashCode()) * 31 + maxPoint.hashCode();
+    }
+
+    private static Map<Integer, BoundingBoxLine> getCache(int dimensionId) {
+        return dimensionCache.computeIfAbsent(dimensionId, i -> new ConcurrentHashMap<>());
+    }
+
+    public static void add(Point minPoint, Point maxPoint, Double width) {
+        int dimensionId = Player.getDimensionId();
+        int cacheKey = getHashKey(minPoint, maxPoint);
+        BoundingBoxLine line = BoundingBoxLine.from(minPoint, maxPoint, width, BoundingBoxType.Custom);
+        getCache(dimensionId).put(cacheKey, line);
+    }
+
+    public static boolean remove(Point min, Point max) {
+        int dimensionId = Player.getDimensionId();
+        int cacheKey = getHashKey(min, max);
+        return getCache(dimensionId).remove(cacheKey) != null;
+    }
+
+    public static void clear() {
+        dimensionCache.values().forEach(Map::clear);
+    }
+
+    public Iterable<BoundingBoxLine> get(int dimensionId) {
+        return getCache(dimensionId).values();
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/client/renderers/LineRenderer.java b/src/main/java/com/irtimaled/bbor/client/renderers/LineRenderer.java
new file mode 100644 (file)
index 0000000..148bcc4
--- /dev/null
@@ -0,0 +1,45 @@
+package com.irtimaled.bbor.client.renderers;
+
+import com.irtimaled.bbor.client.config.ConfigManager;
+import com.irtimaled.bbor.client.models.BoundingBoxLine;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.util.Arrays;
+
+public class LineRenderer extends AbstractRenderer<BoundingBoxLine> {
+    @Override
+    public void render(BoundingBoxLine boundingBox) {
+        Color color = boundingBox.getColor();
+
+        if (boundingBox.getWidth() == 0) {
+            OffsetPoint startPoint = new OffsetPoint(boundingBox.getMinPoint()).offset(0, 0.001f, 0);
+            OffsetPoint endPoint = new OffsetPoint(boundingBox.getMaxPoint()).offset(0, 0.001f, 0);
+            renderLine(startPoint, endPoint, color);
+            return;
+        }
+
+        OffsetPoint[] cornerPoints = Arrays.stream(boundingBox.getCorners()).
+                map(point -> new OffsetPoint(point).offset(0,0.001f, 0)).
+                toArray(OffsetPoint[]::new);
+
+        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
+        Renderer.startQuads()
+                .setColor(color)
+                .addPoints(cornerPoints)
+                .render();
+
+        if(!ConfigManager.fill.get()) return;
+
+        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
+        GL11.glEnable(GL11.GL_BLEND);
+        Renderer.startQuads()
+                .setColor(color)
+                .setAlpha(30)
+                .addPoints(cornerPoints)
+                .render();
+        GL11.glDisable(GL11.GL_BLEND);
+        GL11.glEnable(GL11.GL_POLYGON_OFFSET_LINE);
+        GL11.glPolygonOffset(-1.f, -1.f);
+    }
+}
index fe8564ebbf0b302a77858a68f0856c5aafd07a71..b6ea2c7606e07c06bb47f81572ee79d9aed62250 100644 (file)
@@ -64,6 +64,14 @@ public class Renderer {
         return addPoint(point.getX(), point.getY(), point.getZ());
     }
 
+    public Renderer addPoints(OffsetPoint[] points) {
+        Renderer renderer = this;
+        for (OffsetPoint point : points) {
+            renderer = renderer.addPoint(point);
+        }
+        return renderer;
+    }
+
     Renderer addPoint(double x, double y, double z) {
         pos(x, y, z);
         color();
index 7ff6045bebcc77c72c4df24e31b3d785603532c4..70930d3c37b1ffc70b86daae7f292d3d0c4f976d 100644 (file)
   "bbor.commands.box.cleared": "Box cleared with start [x=%d, y=%d, z=%d] and end [x=%d, y=%d, z=%d]",
   "bbor.commands.box.notFound": "No box found with start [x=%d, y=%d, z=%d] and end [x=%d, y=%d, z=%d]",
 
+  "bbor.commands.line.added": "Line added with start [x=%d, y=%d, z=%d] and end [x=%d, y=%d, z=%d]",
+  "bbor.commands.line.cleared":  "All lines cleared",
+  "bbor.commands.line.cleared.all": "Line cleared with start [x=%d, y=%d, z=%d] and end [x=%d, y=%d, z=%d]",
+  "bbor.commands.line.notFound":  "No line found with start [x=%d, y=%d, z=%d] and end [x=%d, y=%d, z=%d]",
+
   "bbor.commands.spawningSphere.set": "Spawning sphere set",
   "bbor.commands.spawningSphere.notSet": "No spawning sphere set",
   "bbor.commands.spawningSphere.cleared": "Spawning sphere cleared",