From 43c7915e829ad0e1376139759cbc3968adde7fab Mon Sep 17 00:00:00 2001 From: TrollyLoki Date: Mon, 10 Feb 2025 01:25:21 -0500 Subject: [PATCH 1/7] Add support for directional blocks to getRotation functions in RotationUtils --- .../movecraft/repair/util/RotationUtils.java | 95 +++++++++++-------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/repair/util/RotationUtils.java b/src/main/java/net/countercraft/movecraft/repair/util/RotationUtils.java index 9770e00..6a654d9 100644 --- a/src/main/java/net/countercraft/movecraft/repair/util/RotationUtils.java +++ b/src/main/java/net/countercraft/movecraft/repair/util/RotationUtils.java @@ -6,6 +6,7 @@ import org.bukkit.block.data.Rotatable; import org.jetbrains.annotations.Nullable; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.block.BaseBlock; public class RotationUtils { @@ -18,44 +19,60 @@ public class RotationUtils { @Nullable public static BlockFace getRotation(BaseBlock block) { for (var e : block.getStates().entrySet()) { - if (!e.getKey().getName().equals("rotation")) - continue; + String key = e.getKey().getName(); - switch ((int) e.getValue()) { - case 0: - return BlockFace.SOUTH; - case 1: - return BlockFace.SOUTH_SOUTH_WEST; - case 2: - return BlockFace.SOUTH_WEST; - case 3: - return BlockFace.WEST_SOUTH_WEST; - case 4: - return BlockFace.WEST; - case 5: - return BlockFace.WEST_NORTH_WEST; - case 6: - return BlockFace.NORTH_WEST; - case 7: - return BlockFace.NORTH_NORTH_WEST; - case 8: - return BlockFace.NORTH; - case 9: - return BlockFace.NORTH_NORTH_EAST; - case 10: - return BlockFace.NORTH_EAST; - case 11: - return BlockFace.EAST_NORTH_EAST; - case 12: - return BlockFace.EAST; - case 13: - return BlockFace.EAST_SOUTH_EAST; - case 14: - return BlockFace.SOUTH_EAST; - case 15: - return BlockFace.SOUTH_SOUTH_EAST; - default: - return null; + if (key.equals("rotation")) { + // Applies to "floor" signs + switch ((int) e.getValue()) { + case 0: + return BlockFace.SOUTH; + case 1: + return BlockFace.SOUTH_SOUTH_WEST; + case 2: + return BlockFace.SOUTH_WEST; + case 3: + return BlockFace.WEST_SOUTH_WEST; + case 4: + return BlockFace.WEST; + case 5: + return BlockFace.WEST_NORTH_WEST; + case 6: + return BlockFace.NORTH_WEST; + case 7: + return BlockFace.NORTH_NORTH_WEST; + case 8: + return BlockFace.NORTH; + case 9: + return BlockFace.NORTH_NORTH_EAST; + case 10: + return BlockFace.NORTH_EAST; + case 11: + return BlockFace.EAST_NORTH_EAST; + case 12: + return BlockFace.EAST; + case 13: + return BlockFace.EAST_SOUTH_EAST; + case 14: + return BlockFace.SOUTH_EAST; + case 15: + return BlockFace.SOUTH_SOUTH_EAST; + default: + return null; + } + } else if (key.equals("facing")) { + // Applies to wall signs + switch ((Direction) e.getValue()) { + case SOUTH: + return BlockFace.SOUTH; + case WEST: + return BlockFace.WEST; + case NORTH: + return BlockFace.NORTH; + case EAST: + return BlockFace.EAST; + default: + return null; + } } } return null; @@ -70,10 +87,12 @@ public static BlockFace getRotation(BaseBlock block) { @Nullable public static BlockFace getRotation(Block block) { if (block.getBlockData() instanceof Rotatable) { + // Applies to "floor" signs return ((Rotatable) block.getBlockData()).getRotation(); } if (block.getBlockData() instanceof Directional) { - return ((Directional) block.getBlockData()).getFacing().getOppositeFace(); + // Applies to wall signs + return ((Directional) block.getBlockData()).getFacing(); } return null; } From 7ca0615990c5c23667dea6f0278f1ae94ec4a74c Mon Sep 17 00:00:00 2001 From: TrollyLoki Date: Mon, 10 Feb 2025 01:26:25 -0500 Subject: [PATCH 2/7] Simplify calculation of schematic sign position --- .../countercraft/movecraft/repair/types/RepairState.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java index 36104fe..5ee98fe 100644 --- a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java +++ b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java @@ -78,11 +78,7 @@ public String getName() { @NotNull private Clipboard rotate(@NotNull Sign sign) throws WorldEditException { - BlockVector3 signPosition = BlockVector3.at(sign.getX(), sign.getY(), sign.getZ()); - - BlockVector3 offset = signPosition.subtract(schematicSignOffset); - BlockVector3 schematicSignPosition = signPosition.subtract(offset).add(schematicMinPos); - BaseBlock schematicSign = schematic.getFullBlock(schematicSignPosition); + BaseBlock schematicSign = schematic.getFullBlock(schematic.getOrigin()); BlockFace schematicSignFacing = RotationUtils.getRotation(schematicSign); BlockFace worldSignFacing = RotationUtils.getRotation(sign.getBlock()); From 3984443dc2367ebdb7a1232fe42b7781ee090905 Mon Sep 17 00:00:00 2001 From: TrollyLoki Date: Mon, 10 Feb 2025 01:27:48 -0500 Subject: [PATCH 3/7] Rotate repair state based on the rotation of the sign --- .../movecraft/repair/types/RepairState.java | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java index 5ee98fe..e6a98e2 100644 --- a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java +++ b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java @@ -50,9 +50,6 @@ public class RepairState { private final UUID playerUUID; private final String name; private final Clipboard schematic; - private final BlockVector3 schematicMinPos; - private final BlockVector3 schematicSignOffset; - private final BlockVector3 size; public RepairState(@NotNull UUID playerUUID, String name) throws FileNotFoundException, IllegalStateException { this.playerUUID = playerUUID; @@ -63,9 +60,6 @@ public RepairState(@NotNull UUID playerUUID, String name) throws FileNotFoundExc throw new IllegalStateException("Unable to create player directory"); schematic = WEUtils.loadSchematic(playerDirectory, name); - schematicMinPos = schematic.getMinimumPoint(); - schematicSignOffset = schematic.getOrigin().subtract(schematicMinPos); - size = schematic.getDimensions(); } public UUID getUUID() { @@ -91,26 +85,29 @@ private Clipboard rotate(@NotNull Sign sign) throws WorldEditException { @NotNull public ProtoRepair execute(@NotNull Sign sign) throws WorldEditException, ProtoRepairCancelledException { // Rotate repair around the sign - Clipboard clipboard = schematic; - // rotate(sign); + Clipboard clipboard = rotate(sign); // Gather the required materials and tasks - World world = sign.getWorld(); RepairCounter materials = new RepairCounter(); RepairQueue queue = new RepairQueue(); Map blockRepairs = new HashMap<>(); int damagedBlockCount = 0; - Location worldMinPos = sign.getLocation().subtract(schematicSignOffset.getBlockX(), schematicSignOffset.getBlockY(), schematicSignOffset.getBlockZ()); BitmapHitBox hitBox = new BitmapHitBox(); - for (int x = 0; x < size.getBlockX(); x++) { - for (int z = 0; z < size.getBlockZ(); z++) { - for (int y = 0; y < size.getBlockY(); y++) { - BlockVector3 schematicPosition = schematicMinPos.add(x, y, z); + + // We use offsets from the sign (clipboard origin) to calculate actual coordinates + // This is straightforward since we already know the position of the sign in both the schematic and the world + BlockVector3 minOffset = clipboard.getMinimumPoint().subtract(clipboard.getOrigin()); + BlockVector3 maxOffset = clipboard.getMaximumPoint().subtract(clipboard.getOrigin()); + + for (int x = minOffset.x(); x <= maxOffset.x(); x++) { + for (int z = minOffset.z(); z <= maxOffset.z(); z++) { + for (int y = minOffset.y(); y <= maxOffset.y(); y++) { + BlockVector3 schematicPosition = clipboard.getOrigin().add(x, y, z); BaseBlock schematicBlock = clipboard.getFullBlock(schematicPosition); Material schematicMaterial = BukkitAdapter.adapt(schematicBlock.getBlockType()); BlockData schematicData = BukkitAdapter.adapt(schematicBlock); - Location worldPosition = new Location(world, x, y, z).add(worldMinPos); + Location worldPosition = sign.getLocation().add(x, y, z); Block worldBlock = worldPosition.getBlock(); Material worldMaterial = worldBlock.getType(); BlockState worldState = worldBlock.getState(); From 2f15f8841f0cd8d823de7ddf30cc9fe77201cfac Mon Sep 17 00:00:00 2001 From: TrollyLoki Date: Mon, 10 Feb 2025 23:42:38 -0500 Subject: [PATCH 4/7] Use WorldEdit's BukkitAdapter to determine the rotation of schematic blocks --- .../movecraft/repair/types/RepairState.java | 4 +- .../movecraft/repair/util/RotationUtils.java | 81 +++++-------------- 2 files changed, 20 insertions(+), 65 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java index e6a98e2..2cd909b 100644 --- a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java +++ b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java @@ -72,10 +72,10 @@ public String getName() { @NotNull private Clipboard rotate(@NotNull Sign sign) throws WorldEditException { - BaseBlock schematicSign = schematic.getFullBlock(schematic.getOrigin()); + BlockData schematicSign = BukkitAdapter.adapt(schematic.getBlock(schematic.getOrigin())); BlockFace schematicSignFacing = RotationUtils.getRotation(schematicSign); - BlockFace worldSignFacing = RotationUtils.getRotation(sign.getBlock()); + BlockFace worldSignFacing = RotationUtils.getRotation(sign.getBlockData()); int angle = RotationUtils.angleBetweenBlockFaces(worldSignFacing, schematicSignFacing); diff --git a/src/main/java/net/countercraft/movecraft/repair/util/RotationUtils.java b/src/main/java/net/countercraft/movecraft/repair/util/RotationUtils.java index 6a654d9..eeb1565 100644 --- a/src/main/java/net/countercraft/movecraft/repair/util/RotationUtils.java +++ b/src/main/java/net/countercraft/movecraft/repair/util/RotationUtils.java @@ -2,11 +2,12 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; import org.bukkit.block.data.Rotatable; import org.jetbrains.annotations.Nullable; -import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.world.block.BaseBlock; public class RotationUtils { @@ -18,64 +19,7 @@ public class RotationUtils { */ @Nullable public static BlockFace getRotation(BaseBlock block) { - for (var e : block.getStates().entrySet()) { - String key = e.getKey().getName(); - - if (key.equals("rotation")) { - // Applies to "floor" signs - switch ((int) e.getValue()) { - case 0: - return BlockFace.SOUTH; - case 1: - return BlockFace.SOUTH_SOUTH_WEST; - case 2: - return BlockFace.SOUTH_WEST; - case 3: - return BlockFace.WEST_SOUTH_WEST; - case 4: - return BlockFace.WEST; - case 5: - return BlockFace.WEST_NORTH_WEST; - case 6: - return BlockFace.NORTH_WEST; - case 7: - return BlockFace.NORTH_NORTH_WEST; - case 8: - return BlockFace.NORTH; - case 9: - return BlockFace.NORTH_NORTH_EAST; - case 10: - return BlockFace.NORTH_EAST; - case 11: - return BlockFace.EAST_NORTH_EAST; - case 12: - return BlockFace.EAST; - case 13: - return BlockFace.EAST_SOUTH_EAST; - case 14: - return BlockFace.SOUTH_EAST; - case 15: - return BlockFace.SOUTH_SOUTH_EAST; - default: - return null; - } - } else if (key.equals("facing")) { - // Applies to wall signs - switch ((Direction) e.getValue()) { - case SOUTH: - return BlockFace.SOUTH; - case WEST: - return BlockFace.WEST; - case NORTH: - return BlockFace.NORTH; - case EAST: - return BlockFace.EAST; - default: - return null; - } - } - } - return null; + return getRotation(BukkitAdapter.adapt(block)); } /** @@ -86,13 +30,24 @@ public static BlockFace getRotation(BaseBlock block) { */ @Nullable public static BlockFace getRotation(Block block) { - if (block.getBlockData() instanceof Rotatable) { + return getRotation(block.getBlockData()); + } + + /** + * Get the rotation of a Spigot block data + * + * @param blockData Block data to check + * @return Spigot BlockFace to represent the rotation + */ + @Nullable + public static BlockFace getRotation(BlockData blockData) { + if (blockData instanceof Rotatable) { // Applies to "floor" signs - return ((Rotatable) block.getBlockData()).getRotation(); + return ((Rotatable) blockData).getRotation(); } - if (block.getBlockData() instanceof Directional) { + if (blockData instanceof Directional) { // Applies to wall signs - return ((Directional) block.getBlockData()).getFacing(); + return ((Directional) blockData).getFacing(); } return null; } From 2ce3ce4ea22c907e1a7f9cc7d5480d71a23faba3 Mon Sep 17 00:00:00 2001 From: TrollyLoki Date: Tue, 11 Feb 2025 02:19:21 -0500 Subject: [PATCH 5/7] Check sign rotation before using cached ProtoRepairs Fixes an edge case that occurred if a repair sign was precisely on the craft's center of rotation. The issue occurred if a player right-clicked the sign once, rotated the craft, and then right-clicked the sign again in quick succession. This caused the repair to begin as if the craft had not been rotated. --- .../movecraft/repair/types/ProtoRepair.java | 12 +++++++++++- .../movecraft/repair/types/RepairState.java | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/repair/types/ProtoRepair.java b/src/main/java/net/countercraft/movecraft/repair/types/ProtoRepair.java index ed5949c..78af0dd 100644 --- a/src/main/java/net/countercraft/movecraft/repair/types/ProtoRepair.java +++ b/src/main/java/net/countercraft/movecraft/repair/types/ProtoRepair.java @@ -9,6 +9,7 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.Container; import org.bukkit.block.Sign; @@ -24,6 +25,7 @@ import net.countercraft.movecraft.repair.config.Config; import net.countercraft.movecraft.repair.events.RepairPreStartedEvent; import net.countercraft.movecraft.repair.types.blobs.RepairBlob; +import net.countercraft.movecraft.repair.util.RotationUtils; import net.countercraft.movecraft.util.Counter; import net.countercraft.movecraft.util.MathUtils; import net.countercraft.movecraft.util.Pair; @@ -36,18 +38,20 @@ public class ProtoRepair { private final RepairCounter materials; private final int damagedBlockCount; private final MovecraftLocation origin; + private final BlockFace rotation; private final World world; private final HitBox hitBox; private final long calculationTime; private boolean valid; public ProtoRepair(UUID playerUUID, String name, RepairQueue queue, RepairCounter materials, int damagedBlockCount, - MovecraftLocation origin, World world, HitBox hitBox) { + MovecraftLocation origin, BlockFace rotation, World world, HitBox hitBox) { this.playerUUID = playerUUID; this.name = name; this.queue = queue; this.materials = materials; this.origin = origin; + this.rotation = rotation; this.world = world; this.hitBox = hitBox; this.damagedBlockCount = damagedBlockCount; @@ -75,6 +79,10 @@ public MovecraftLocation getOrigin() { return origin; } + public BlockFace getRotation() { + return rotation; + } + public World getWorld() { return world; } @@ -95,6 +103,8 @@ public Repair execute(@NotNull Craft craft, Sign sign) throw new ProtoRepairExpiredException(); // Check for expired if (!origin.equals(MathUtils.bukkit2MovecraftLoc(sign.getLocation()))) throw new ProtoRepairLocationException(); // Check for origin + if (!rotation.equals(RotationUtils.getRotation(sign.getBlockData()))) + throw new ProtoRepairLocationException(); // Check for rotation // Check for balance double cost = 0; diff --git a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java index 2cd909b..319bdc1 100644 --- a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java +++ b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java @@ -177,7 +177,7 @@ public ProtoRepair execute(@NotNull Sign sign) throws WorldEditException, ProtoR } } - ProtoRepair result = new ProtoRepair(playerUUID, name, queue, materials, damagedBlockCount, MathUtils.bukkit2MovecraftLoc(sign.getLocation()), sign.getWorld(), hitBox); + ProtoRepair result = new ProtoRepair(playerUUID, name, queue, materials, damagedBlockCount, MathUtils.bukkit2MovecraftLoc(sign.getLocation()), RotationUtils.getRotation(sign.getBlockData()), sign.getWorld(), hitBox); ProtoRepairCreateEvent event = new ProtoRepairCreateEvent(result); Bukkit.getPluginManager().callEvent(event); From 06800c0ab8f04adfde94a598e26db8023772a8d2 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sun, 16 Mar 2025 11:26:30 -0500 Subject: [PATCH 6/7] Expand exceptions to add rotation --- .../net/countercraft/movecraft/repair/RepairSign.java | 6 +++--- .../countercraft/movecraft/repair/types/ProtoRepair.java | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/repair/RepairSign.java b/src/main/java/net/countercraft/movecraft/repair/RepairSign.java index 9ba6d1a..5583315 100644 --- a/src/main/java/net/countercraft/movecraft/repair/RepairSign.java +++ b/src/main/java/net/countercraft/movecraft/repair/RepairSign.java @@ -123,10 +123,10 @@ public void onRightClick(Sign sign, @NotNull Player player, PlayerCraft craft) { return; } catch (ProtoRepair.ItemRemovalException e) { player.sendMessage(I18nSupport.getInternationalisedComponent("Repair - Removal exception")); - return; - } catch (ProtoRepair.ProtoRepairExpiredException | ProtoRepair.ProtoRepairLocationException e) { - // Expired or wrong location, go back to first click // ItemRemovalException shouldn't happen, but go back to first click regardless + return; + } catch (ProtoRepair.ProtoRepairExpiredException | ProtoRepair.ProtoRepairLocationException | ProtoRepair.ProtoRepairRotationException e) { + // Expired, wrong location or rotation, go back to first click createProtoRepair(sign, uuid, player, craft); return; } catch (ProtoRepair.CancelledException e) { diff --git a/src/main/java/net/countercraft/movecraft/repair/types/ProtoRepair.java b/src/main/java/net/countercraft/movecraft/repair/types/ProtoRepair.java index 78af0dd..fe1a9ef 100644 --- a/src/main/java/net/countercraft/movecraft/repair/types/ProtoRepair.java +++ b/src/main/java/net/countercraft/movecraft/repair/types/ProtoRepair.java @@ -97,14 +97,14 @@ public boolean isInvalid() { @NotNull public Repair execute(@NotNull Craft craft, Sign sign) - throws ProtoRepairExpiredException, ProtoRepairLocationException, ItemRemovalException, - NotEnoughItemsException, NotEnoughMoneyException { + throws ProtoRepairExpiredException, ProtoRepairLocationException, ProtoRepairRotationException, + ItemRemovalException, NotEnoughItemsException, NotEnoughMoneyException { if (isInvalid()) throw new ProtoRepairExpiredException(); // Check for expired if (!origin.equals(MathUtils.bukkit2MovecraftLoc(sign.getLocation()))) throw new ProtoRepairLocationException(); // Check for origin if (!rotation.equals(RotationUtils.getRotation(sign.getBlockData()))) - throw new ProtoRepairLocationException(); // Check for rotation + throw new ProtoRepairRotationException(); // Check for rotation // Check for balance double cost = 0; @@ -255,6 +255,9 @@ public static class ProtoRepairExpiredException extends IllegalStateException { public static class ProtoRepairLocationException extends IllegalStateException { } + public static class ProtoRepairRotationException extends IllegalStateException { + } + public static class CancelledException extends IllegalStateException { } } From 54aeed266bedc0a0c223e2cbb0c197dc68f642e1 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sun, 16 Mar 2025 11:29:47 -0500 Subject: [PATCH 7/7] Clean up offset math --- .../countercraft/movecraft/repair/types/RepairState.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java index 319bdc1..fdec702 100644 --- a/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java +++ b/src/main/java/net/countercraft/movecraft/repair/types/RepairState.java @@ -96,13 +96,14 @@ public ProtoRepair execute(@NotNull Sign sign) throws WorldEditException, ProtoR // We use offsets from the sign (clipboard origin) to calculate actual coordinates // This is straightforward since we already know the position of the sign in both the schematic and the world - BlockVector3 minOffset = clipboard.getMinimumPoint().subtract(clipboard.getOrigin()); - BlockVector3 maxOffset = clipboard.getMaximumPoint().subtract(clipboard.getOrigin()); + BlockVector3 clipboardOrigin = clipboard.getOrigin(); + BlockVector3 minOffset = clipboard.getMinimumPoint().subtract(clipboardOrigin); + BlockVector3 maxOffset = clipboard.getMaximumPoint().subtract(clipboardOrigin); for (int x = minOffset.x(); x <= maxOffset.x(); x++) { for (int z = minOffset.z(); z <= maxOffset.z(); z++) { for (int y = minOffset.y(); y <= maxOffset.y(); y++) { - BlockVector3 schematicPosition = clipboard.getOrigin().add(x, y, z); + BlockVector3 schematicPosition = clipboardOrigin.add(x, y, z); BaseBlock schematicBlock = clipboard.getFullBlock(schematicPosition); Material schematicMaterial = BukkitAdapter.adapt(schematicBlock.getBlockType()); BlockData schematicData = BukkitAdapter.adapt(schematicBlock);