diff --git a/src/main/java/carpet/commands/DrawCommand.java b/src/main/java/carpet/commands/DrawCommand.java index e2ca0bb3..ed53dfb5 100644 --- a/src/main/java/carpet/commands/DrawCommand.java +++ b/src/main/java/carpet/commands/DrawCommand.java @@ -6,10 +6,12 @@ import carpet.utils.Messenger; import com.google.common.collect.Lists; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.arguments.BoolArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.Block; import net.minecraft.block.pattern.CachedBlockPosition; import net.minecraft.server.command.ServerCommandSource; @@ -17,11 +19,11 @@ import net.minecraft.command.arguments.BlockPosArgumentType; import net.minecraft.command.arguments.BlockPredicateArgumentType; import net.minecraft.command.arguments.BlockStateArgument; import net.minecraft.command.arguments.BlockStateArgumentType; -import static net.minecraft.server.command.CommandSource.suggestMatching; import net.minecraft.inventory.Inventory; import net.minecraft.block.entity.BlockEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.MathHelper; import java.util.List; import java.util.function.Predicate; @@ -29,6 +31,7 @@ import java.lang.Math; import static net.minecraft.server.command.CommandManager.argument; import static net.minecraft.server.command.CommandManager.literal; +import static net.minecraft.server.command.CommandSource.suggestMatching; public class DrawCommand { @@ -37,103 +40,130 @@ public class DrawCommand LiteralArgumentBuilder command = literal("draw"). requires((player) -> SettingsManager.canUseCommand(player, CarpetSettings.commandDraw)). then(literal("sphere"). - then(argument("center", BlockPosArgumentType.blockPos()). - then(argument("radius", IntegerArgumentType.integer(1)). - then(argument("block", BlockStateArgumentType.blockState()). - executes((c) -> drawSphere(c.getSource(), - BlockPosArgumentType.getBlockPos(c, "center"), - IntegerArgumentType.getInteger(c, "radius"), - BlockStateArgumentType.getBlockState(c, "block"), null)) - .then(literal("replace") - .then(argument("filter", BlockPredicateArgumentType.blockPredicate()) - .executes((c) -> drawSphere(c.getSource(), - BlockPosArgumentType.getBlockPos(c, "center"), - IntegerArgumentType.getInteger(c, "radius"), - BlockStateArgumentType.getBlockState(c, "block"), - BlockPredicateArgumentType.getBlockPredicate(c, - "filter"))))))))) - .then(literal("diamond").then(argument("center", BlockPosArgumentType.blockPos()) - .then(argument("radius", IntegerArgumentType.integer(1)) - .then(argument("block", BlockStateArgumentType.blockState()) - .executes((c) -> drawDiamond(c.getSource(), - BlockPosArgumentType.getBlockPos(c, "center"), - IntegerArgumentType.getInteger(c, "radius"), - BlockStateArgumentType.getBlockState(c, "block"), null)) - .then(literal("replace") - .then(argument("filter", BlockPredicateArgumentType.blockPredicate()) - .executes((c) -> drawDiamond(c.getSource(), - BlockPosArgumentType.getBlockPos(c, "center"), - IntegerArgumentType.getInteger(c, "radius"), - BlockStateArgumentType.getBlockState(c, "block"), - BlockPredicateArgumentType.getBlockPredicate(c,"filter") - ) - ) - ) - ) - ) - ) - ) - ) - .then(literal("pyramid") - .then(argument("center", BlockPosArgumentType.blockPos()) - .then(argument("radius", IntegerArgumentType.integer(1)) - .then(argument("height",IntegerArgumentType.integer(1)) - .then(argument("pointing up?",BoolArgumentType.bool()) - .then(argument("type",StringArgumentType.string()) - .suggests( (c, b) -> suggestMatching(new String[]{"square","circle"},b)) - .then(argument("orientation",StringArgumentType.string()) - .suggests( (c, b) -> suggestMatching(new String[]{"x","y","z"},b)) - .then(argument("block", BlockStateArgumentType.blockState()) - .executes((c) -> drawPyramid(c.getSource(), - BlockPosArgumentType.getBlockPos(c, "center"), - StringArgumentType.getString(c,"type"), - IntegerArgumentType.getInteger(c, "radius"), - IntegerArgumentType.getInteger(c, "height"), - BoolArgumentType.getBool(c,"pointing up?"), - StringArgumentType.getString(c,"orientation"), - BlockStateArgumentType.getBlockState(c, "block"), null) - ) - .then(literal("replace") - .then(argument("filter", BlockPredicateArgumentType.blockPredicate()) - .executes((c) -> drawPyramid(c.getSource(), - BlockPosArgumentType.getBlockPos(c, "center"), - StringArgumentType.getString(c,"type"), - IntegerArgumentType.getInteger(c, "radius"), - IntegerArgumentType.getInteger(c, "height"), - BoolArgumentType.getBool(c,"pointing up?"), - StringArgumentType.getString(c,"orientation"), - BlockStateArgumentType.getBlockState(c, "block"), - BlockPredicateArgumentType.getBlockPredicate(c,"filter") - ) - ) - ) - ) - ) - ) - ) - ) - ) - ) - ) - ); + then(argument("center", BlockPosArgumentType.blockPos()). + then(argument("radius", IntegerArgumentType.integer(1)). + then(drawShape(c -> DrawCommand.drawSphere(c, false)))))). + then(literal("ball"). + then(argument("center", BlockPosArgumentType.blockPos()). + then(argument("radius", IntegerArgumentType.integer(1)). + then(drawShape(c -> DrawCommand.drawSphere(c, true)))))). + then(literal("diamond"). + then(argument("center", BlockPosArgumentType.blockPos()). + then(argument("radius", IntegerArgumentType.integer(1)). + then(drawShape(c -> DrawCommand.drawDiamond(c, true)))))). + then(literal("pyramid"). + then(argument("center", BlockPosArgumentType.blockPos()). + then(argument("radius", IntegerArgumentType.integer(1)). + then(argument("height",IntegerArgumentType.integer(1)). + then(argument("pointing",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"up","down"},b)). + then(argument("orientation",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"y","x","z"},b)). + then(drawShape(c -> DrawCommand.drawPyramid(c, "square", true))))))))). + then(literal("cone"). + then(argument("center", BlockPosArgumentType.blockPos()). + then(argument("radius", IntegerArgumentType.integer(1)). + then(argument("height",IntegerArgumentType.integer(1)). + then(argument("pointing",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"up","down"},b)). + then(argument("orientation",StringArgumentType.word()).suggests( (c, b) -> suggestMatching(new String[]{"y","x","z"},b)) + .then(drawShape(c -> DrawCommand.drawPyramid(c, "circle", true))))))))); dispatcher.register(command); } - private static int drawSphere(ServerCommandSource source, BlockPos pos, int radius, BlockStateArgument block, - Predicate replacement) + @FunctionalInterface + private interface OptionalBlockSelector { - return drawSphere(source, pos, (double) radius, (double) radius, (double) radius, block, replacement, false); + Integer apply(final CommandContext ctx) throws CommandSyntaxException; } - private static int drawSphere(ServerCommandSource source, BlockPos pos, double radiusX, double radiusY, - double radiusZ, BlockStateArgument block, Predicate replacement, boolean solid) + @FunctionalInterface + private interface ArgumentExtractor { - int affected = 0; - ServerWorld world = source.getWorld(); + T apply(final CommandContext ctx, final String argName) throws CommandSyntaxException; + } - radiusX += 0.5; - radiusY += 0.5; - radiusZ += 0.5; + private static RequiredArgumentBuilder + drawShape(OptionalBlockSelector drawer) + { + return argument("block", BlockStateArgumentType.blockState()). + executes(drawer::apply) + .then(literal("replace") + .then(argument("filter", BlockPredicateArgumentType.blockPredicate()) + .executes(drawer::apply))); + } + + private static class ErrorHandled extends RuntimeException {} + + private static T getArg(CommandContext ctx, ArgumentExtractor extract, String hwat) throws CommandSyntaxException + { + return getArg(ctx, extract, hwat, false); + } + + private static T getArg(CommandContext ctx, ArgumentExtractor extract, String hwat, boolean optional) throws CommandSyntaxException + { + T arg = null; + try + { + arg = extract.apply(ctx, hwat); + } + catch (IllegalArgumentException e) + { + if (optional) return null; + Messenger.m(ctx.getSource(), "rb Missing "+hwat); + throw new ErrorHandled(); + } + return arg; + } + + private static double lengthSq(double x, double y, double z) + { + return (x * x) + (y * y) + (z * z); + } + + private static int setBlock( + ServerWorld world, BlockPos.Mutable mbpos, int x, int y, int z, + BlockStateArgument block, Predicate replacement, + List list + ) + { + mbpos.set(x, y, z); + int success=0; + if (replacement == null || replacement.test(new CachedBlockPosition(world, mbpos, true))) + { + BlockEntity tileentity = world.getBlockEntity(mbpos); + if (tileentity instanceof Inventory) + { + ((Inventory) tileentity).clear(); + } + if (block.setBlockState(world, mbpos, 2)) + { + list.add(mbpos.toImmutable()); + ++success; + } + } + + return success; + } + + private static int drawSphere(CommandContext ctx, boolean solid) throws CommandSyntaxException + { + BlockPos pos; + int radius; + BlockStateArgument block; + Predicate replacement; + try + { + pos = getArg(ctx, BlockPosArgumentType::getBlockPos, "center"); + radius = getArg(ctx, IntegerArgumentType::getInteger, "radius"); + block = getArg(ctx, BlockStateArgumentType::getBlockState, "block"); + replacement = getArg(ctx, BlockPredicateArgumentType::getBlockPredicate, "filter", true); + } + catch (ErrorHandled ignored) { return 0; } + + int affected = 0; + ServerWorld world = ctx.getSource().getWorld(); + + double radiusX = radius+0.5; + double radiusY = radius+0.5; + double radiusZ = radius+0.5; final double invRadiusX = 1 / radiusX; final double invRadiusY = 1 / radiusY; @@ -148,22 +178,28 @@ public class DrawCommand double nextXn = 0; - forX: for (int x = 0; x <= ceilRadiusX; ++x) { + forX: for (int x = 0; x <= ceilRadiusX; ++x) + { final double xn = nextXn; nextXn = (x + 1) * invRadiusX; double nextYn = 0; - forY: for (int y = 0; y <= ceilRadiusY; ++y) { + forY: for (int y = 0; y <= ceilRadiusY; ++y) + { final double yn = nextYn; nextYn = (y + 1) * invRadiusY; double nextZn = 0; - forZ: for (int z = 0; z <= ceilRadiusZ; ++z) { + forZ: for (int z = 0; z <= ceilRadiusZ; ++z) + { final double zn = nextZn; nextZn = (z + 1) * invRadiusZ; double distanceSq = lengthSq(xn, yn, zn); - if (distanceSq > 1) { - if (z == 0) { - if (y == 0) { + if (distanceSq > 1) + { + if (z == 0) + { + if (y == 0) + { break forX; } break forY; @@ -171,11 +207,9 @@ public class DrawCommand break forZ; } - if (!solid) { - if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) - { - continue; - } + if (!solid && lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) + { + continue; } CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates; @@ -185,22 +219,10 @@ public class DrawCommand { for (int zmod = -1; zmod < 2; zmod += 2) { - mbpos.set(pos.getX() + xmod * x, pos.getY() + ymod * y, pos.getZ() + zmod * z); - if (replacement == null - || replacement.test(new CachedBlockPosition(world, mbpos, true))) - { - BlockEntity tileentity = world.getBlockEntity(mbpos); - if (tileentity instanceof Inventory) - { - ((Inventory) tileentity).clear(); - } - - if (block.setBlockState(world, mbpos, 2)) - { - list.add(mbpos.toImmutable()); - ++affected; - } - } + affected+= setBlock(world, mbpos, + pos.getX() + xmod * x, pos.getY() + ymod * y, pos.getZ() + zmod * z, + block, replacement, list + ); } } } @@ -208,48 +230,31 @@ public class DrawCommand } } } - if (CarpetSettings.fillUpdates) { - - for (BlockPos blockpos1 : list) { - Block blokc = world.getBlockState(blockpos1).getBlock(); - world.updateNeighbors(blockpos1, blokc); // or always version???? - } + if (CarpetSettings.fillUpdates) + { + list.forEach(blockpos1 -> world.updateNeighbors(blockpos1, world.getBlockState(blockpos1).getBlock())); } - Messenger.m(source, "gi Filled " + affected + " blocks"); - - return 1; + Messenger.m(ctx.getSource(), "gi Filled " + affected + " blocks"); + return affected; } - private static double lengthSq(double x, double y, double z) { - return (x * x) + (y * y) + (z * z); - } - - private static int blockset(ServerCommandSource source, int x, int y, int z, Predicate replacement, List list, - BlockPos.Mutable mbpos, BlockStateArgument block){ - ServerWorld world = source.getWorld(); - mbpos.set(x, y, z); - int success=0; - if (replacement == null || replacement.test(new CachedBlockPosition(world, mbpos, true))) { - BlockEntity tileentity = world.getBlockEntity(mbpos); - if (tileentity instanceof Inventory) { - ((Inventory) tileentity).clear(); - } - if (block.setBlockState(world, mbpos, 2)) { - list.add(mbpos.toImmutable()); - ++success; - } + private static int drawDiamond(CommandContext ctx, boolean solid) throws CommandSyntaxException + { + BlockPos pos; + int radius; + BlockStateArgument block; + Predicate replacement; + try + { + pos = getArg(ctx, BlockPosArgumentType::getBlockPos, "center"); + radius = getArg(ctx, IntegerArgumentType::getInteger, "radius"); + block = getArg(ctx, BlockStateArgumentType::getBlockState, "block"); + replacement = getArg(ctx, BlockPredicateArgumentType::getBlockPredicate, "filter", true); } + catch (ErrorHandled ignored) { return 0; } - return success; - } + ServerCommandSource source = ctx.getSource(); - private static int drawDiamond(ServerCommandSource source, BlockPos pos, int radius, BlockStateArgument block, - Predicate replacement) { - return (int) drawDiamond(source, pos, radius, block, replacement, false); - } - - private static int drawDiamond(ServerCommandSource source, BlockPos pos, int radius,BlockStateArgument block, - Predicate replacement, boolean solid) { int affected=0; BlockPos.Mutable mbpos = new BlockPos.Mutable(pos); @@ -259,78 +264,100 @@ public class DrawCommand CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates; - for (int r = 0; r < radius; ++r) { + for (int r = 0; r < radius; ++r) + { int y=r-radius+1; - for (int x = -r; x <= r; ++x) { + for (int x = -r; x <= r; ++x) + { int z=r-Math.abs(x); - affected+=blockset(source, pos.getX()+x, pos.getY()-y, pos.getZ()+z, replacement, list, mbpos, block); - affected+=blockset(source, pos.getX()+x, pos.getY()-y, pos.getZ()-z, replacement, list, mbpos, block); - affected+=blockset(source, pos.getX()+x, pos.getY()+y, pos.getZ()+z, replacement, list, mbpos, block); - affected+=blockset(source, pos.getX()+x, pos.getY()+y, pos.getZ()-z, replacement, list, mbpos, block); + affected+= setBlock(world, mbpos, pos.getX()+x, pos.getY()-y, pos.getZ()+z, block, replacement, list); + affected+= setBlock(world, mbpos, pos.getX()+x, pos.getY()-y, pos.getZ()-z, block, replacement, list); + affected+= setBlock(world, mbpos, pos.getX()+x, pos.getY()+y, pos.getZ()+z, block, replacement, list); + affected+= setBlock(world, mbpos, pos.getX()+x, pos.getY()+y, pos.getZ()-z, block, replacement, list); } } CarpetSettings.impendingFillSkipUpdates = false; - if (CarpetSettings.fillUpdates) { - - for (BlockPos blockpos1 : list) { - Block blokc = world.getBlockState(blockpos1).getBlock(); - world.updateNeighbors(blockpos1, blokc); - } + if (CarpetSettings.fillUpdates) + { + list.forEach(p -> world.updateNeighbors(p, world.getBlockState(p).getBlock())); } Messenger.m(source, "gi Filled " + affected + " blocks"); - return 1; + return affected; } - private static int drawCircle(ServerCommandSource source, BlockPos pos, int offset, int radius,BlockStateArgument block, String orientation, - Predicate replacement, List list, BlockPos.Mutable mbpos){ + private static int fillFlat( + ServerWorld world, BlockPos pos, int offset, double dr, boolean rectangle, String orientation, + BlockStateArgument block, Predicate replacement, + List list, BlockPos.Mutable mbpos + ) + { int successes=0; - for(int axis1=-radius;axis1<=radius;++axis1){ - - for(int axis2=-radius;axis2<=radius;++axis2){ - - if(axis1*axis1+axis2*axis2<=radius*radius){ - switch (orientation){ - case "x":successes+=blockset(source, pos.getX()+offset, pos.getY()+axis1, pos.getZ()+axis2,replacement, list, mbpos, block);break; - case "y":successes+=blockset(source, pos.getX()+axis1, pos.getY()+offset, pos.getZ()+axis2,replacement, list, mbpos, block);break; - case "z":successes+=blockset(source, pos.getX()+axis2, pos.getY()+axis1, pos.getZ()+offset,replacement, list, mbpos, block);break; - default:Messenger.m(source,"gi Invalid orientation, must be x, y or z");return 0; - } - } + int r = MathHelper.floor(dr); + double drsq = dr*dr; + if (orientation.equalsIgnoreCase("x")) + { + for(int a=-r; a<=r; ++a) for(int b=-r; b<=r; ++b) if(rectangle || a*a + b*b <= drsq) + { + successes += setBlock( + world, mbpos,pos.getX()+offset, pos.getY()+a, pos.getZ()+b, + block, replacement, list + ); } + return successes; } - return successes; - } - private static int drawSquare(ServerCommandSource source, BlockPos pos, int offset, int radius, BlockStateArgument block, String orientation, - Predicate replacement, List list, BlockPos.Mutable mbpos){ - int success=0; - - for(int axis1=-radius;axis1<=radius;++axis1){ - - for(int axis2=-radius;axis2<=radius;++axis2){ - switch (orientation){ - case "x":success+=blockset(source, pos.getX()+offset, pos.getY()+axis1, pos.getZ()+axis2,replacement, list, mbpos, block);break; - case "y":success+=blockset(source, pos.getX()+axis1, pos.getY()+offset, pos.getZ()+axis2,replacement, list, mbpos, block);break; - case "z":success+=blockset(source, pos.getX()+axis2, pos.getY()+axis1, pos.getZ()+offset,replacement, list, mbpos, block);break; - default:Messenger.m(source,"gi Invalid orientation, must be x, y or z");return 0; - } + if (orientation.equalsIgnoreCase("y")) + { + for(int a=-r; a<=r; ++a) for(int b=-r; b<=r; ++b) if(rectangle || a*a + b*b <= drsq) + { + successes += setBlock( + world, mbpos,pos.getX()+a, pos.getY()+offset, pos.getZ()+b, + block, replacement, list + ); } + return successes; } - - return success; - } - - private static int drawPyramid(ServerCommandSource source, BlockPos pos, String shape, int radius, int height, boolean pointup, String orientation, BlockStateArgument block, - Predicate replacement) { - return (int) drawPyramid(source, pos, radius, height, block, replacement, pointup, orientation, false, shape); + if (orientation.equalsIgnoreCase("z")) + { + for(int a=-r; a<=r; ++a) for(int b=-r; b<=r; ++b) if(rectangle || a*a + b*b <= drsq) + { + successes += setBlock( + world, mbpos,pos.getX()+b, pos.getY()+a, pos.getZ()+offset, + block, replacement, list + ); + } + return successes; + } + return 0; } - private static double drawPyramid(ServerCommandSource source, BlockPos pos, int radius, int height, BlockStateArgument block, - Predicate replacement, boolean pointup, String orientation, boolean solid, String shape) { + private static int drawPyramid(CommandContext ctx, String base, boolean solid) throws CommandSyntaxException + { + BlockPos pos; + double radius; + int height; + boolean pointup; + String orientation; + BlockStateArgument block; + Predicate replacement; + try + { + pos = getArg(ctx, BlockPosArgumentType::getBlockPos, "center"); + radius = getArg(ctx, IntegerArgumentType::getInteger, "radius")+0.5D; + height = getArg(ctx, IntegerArgumentType::getInteger, "height"); + pointup = getArg(ctx, StringArgumentType::getString, "pointing").equalsIgnoreCase("up"); + orientation = getArg(ctx, StringArgumentType::getString,"orientation"); + block = getArg(ctx, BlockStateArgumentType::getBlockState, "block"); + replacement = getArg(ctx, BlockPredicateArgumentType::getBlockPredicate, "filter", true); + } + catch (ErrorHandled ignored) { return 0; } + + ServerCommandSource source = ctx.getSource(); + int affected = 0; BlockPos.Mutable mbpos = new BlockPos.Mutable(pos); @@ -340,22 +367,12 @@ public class DrawCommand CarpetSettings.impendingFillSkipUpdates = !CarpetSettings.fillUpdates; - int r = radius; + boolean isSquare = base.equalsIgnoreCase("square"); - for(int i =0; i