From 715204325e119bee79fda927fd84d6a1c0cfe97c Mon Sep 17 00:00:00 2001 From: Intybyte Date: Sun, 21 Sep 2025 21:17:24 +0200 Subject: [PATCH 01/48] Add SchematicLib dependency and add necessary classes --- cannons-bukkit/pom.xml | 9 +++ .../cannons/schematic/block/BlockImpl.java | 35 +++++++++++ .../schematic/block/WorldEditBlock.java | 36 +++++++++++ .../schematic/formats/WorldEditFormat.java | 63 +++++++++++++++++++ .../namespace/MinecraftNamespaceHandler.java | 32 ++++++++++ .../world/SchematicWorldProcessorImpl.java | 19 ++++++ 6 files changed, 194 insertions(+) create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/WorldEditBlock.java create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 073173a6..984c603b 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -122,6 +122,11 @@ 1.0.7 compile + + com.github.Intybyte + SchematicLib + 5acc213e0c + @@ -241,6 +246,10 @@ io.papermc.lib at.pavlov.cannons.shaded.paperlib + + me.vaan + at.pavlov.cannons.shaded.vaan + diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java new file mode 100644 index 00000000..6723ba4a --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java @@ -0,0 +1,35 @@ +package at.pavlov.cannons.schematic.block; + +import me.vaan.schematiclib.base.block.BlockKey; +import me.vaan.schematiclib.base.block.IBlock; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; + +public class BlockImpl implements IBlock { + private final Block block; + + public BlockImpl(Block block) { + this.block = block; + } + + @Override + public int x() { + return block.getX(); + } + + @Override + public int y() { + return block.getY(); + } + + @Override + public int z() { + return block.getZ(); + } + + @Override + public BlockKey key() { + NamespacedKey key = block.getType().getKey(); + return BlockKey.mc(key.getKey()); + } +} \ No newline at end of file diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/WorldEditBlock.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/WorldEditBlock.java new file mode 100644 index 00000000..abcb25b0 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/WorldEditBlock.java @@ -0,0 +1,36 @@ +package at.pavlov.cannons.schematic.block; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import lombok.AllArgsConstructor; +import me.vaan.schematiclib.base.block.BlockKey; +import me.vaan.schematiclib.base.block.IBlock; + +@AllArgsConstructor +public class WorldEditBlock implements IBlock { + private final BlockState state; + private final BlockVector3 pos; + + @Override + public int x() { + return pos.getBlockX(); + } + + @Override + public int y() { + return pos.getBlockY(); + } + + @Override + public int z() { + return pos.getBlockZ(); + } + + @Override + public BlockKey key() { + String id = state.getBlockType().getId(); + String[] splitted = id.split(":"); + return new BlockKey(splitted[0], splitted[1]); + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java new file mode 100644 index 00000000..4a5e9c60 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java @@ -0,0 +1,63 @@ +package at.pavlov.cannons.schematic.formats; + +import at.pavlov.cannons.Cannons; +import at.pavlov.cannons.schematic.block.WorldEditBlock; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.io.Closer; +import com.sk89q.worldedit.world.block.BlockState; +import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.formats.FileExceptionUnknown; +import me.vaan.schematiclib.base.formats.SchematicLoader; +import me.vaan.schematiclib.base.schematic.Schematic; +import me.vaan.schematiclib.file.schematic.FileSchematic; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class WorldEditFormat implements SchematicLoader { + @Override + public Schematic load(File file) throws Throwable { + Clipboard cc = loadSchematic(file); + if (cc == null) throw new FileExceptionUnknown("Schematic not found"); + + Region region = cc.getRegion(); + + List positions = new ArrayList<>(); + + for (BlockVector3 pos : region) { + BlockState state = cc.getBlock(pos); + positions.add(new WorldEditBlock(state, pos)); + } + + return new FileSchematic(positions); + } + + private Clipboard loadSchematic(File schematicFile) { + ClipboardFormat format = ClipboardFormats.findByFile(schematicFile); + + if(format == null) { + Cannons.getPlugin().logSevere("Error while loading schematic " + schematicFile.getPath() + " : Format not found"); + return null; + } + + try (Closer closer = Closer.create()) { + FileInputStream fis = closer.register(new FileInputStream(schematicFile)); + BufferedInputStream bis = closer.register(new BufferedInputStream(fis)); + ClipboardReader reader = closer.register(format.getReader(bis)); + + return reader.read(); + } catch (IOException e) { + Cannons.getPlugin().logSevere("Error while loading schematic " + schematicFile.getPath() + " : IO Error"); + return null; + } + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java new file mode 100644 index 00000000..cefc32c5 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java @@ -0,0 +1,32 @@ +package at.pavlov.cannons.schematic.namespace; + + +import at.pavlov.cannons.schematic.block.BlockImpl; +import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.namespace.NamespaceHandler; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; + +import java.util.UUID; + +public class MinecraftNamespaceHandler implements NamespaceHandler { + @Override + public void place(IBlock iBlock, UUID uuid) { + NamespacedKey key = new NamespacedKey("minecraft", iBlock.key().key()); + Material mat = Registry.MATERIAL.get(key); + Bukkit.getWorld(uuid).getBlockAt( + iBlock.x(), + iBlock.y(), + iBlock.z() + ).setType(mat); + } + + @Override + public IBlock get(int x, int y, int z, UUID uuid) { + return new BlockImpl( + Bukkit.getWorld(uuid).getBlockAt(x, y, z) + ); + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java new file mode 100644 index 00000000..dda61483 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java @@ -0,0 +1,19 @@ +package at.pavlov.cannons.schematic.world; + +import at.pavlov.cannons.schematic.namespace.MinecraftNamespaceHandler; +import me.vaan.schematiclib.base.namespace.NamespaceRegistry; +import me.vaan.schematiclib.base.world.SchematicWorldProcessor; + +public class SchematicWorldProcessorImpl implements SchematicWorldProcessor { + private final NamespaceRegistry registry; + + public SchematicWorldProcessorImpl() { + this.registry = new NamespaceRegistry("minecraft", new MinecraftNamespaceHandler()); + } + + @Override + public NamespaceRegistry registry() { + return registry; + } +} + From 21fc44072ba43dbc2b2309081bcac464e6fb4742 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Sun, 21 Sep 2025 21:21:32 +0200 Subject: [PATCH 02/48] Small changes to SimpleBlock --- .../pavlov/cannons/container/SimpleBlock.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/container/SimpleBlock.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/container/SimpleBlock.java index b8de6cc1..3dd1a8ca 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/container/SimpleBlock.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/container/SimpleBlock.java @@ -18,6 +18,7 @@ public class SimpleBlock { private int locX; private int locY; private int locZ; + private Material material; private BlockData blockData; public SimpleBlock(int x, int y, int z, BlockData blockData) { @@ -25,6 +26,7 @@ public SimpleBlock(int x, int y, int z, BlockData blockData) { locY = y; locZ = z; + this.material = blockData.getMaterial(); this.blockData = blockData; } @@ -41,11 +43,7 @@ private SimpleBlock(Vector vect, Material material) { } public SimpleBlock(Location loc, Material material) { - locX = loc.getBlockX(); - locY = loc.getBlockY(); - locZ = loc.getBlockZ(); - - this.blockData = material.createBlockData(); + this(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), material); } @@ -90,7 +88,7 @@ public boolean compareMaterial(World world, Vector offset) { * @return true if both block match */ public boolean compareMaterial(BlockData block) { - return block.getMaterial().equals(this.blockData.getMaterial()); + return block.getMaterial().equals(this.material); } /** @@ -99,7 +97,7 @@ public boolean compareMaterial(BlockData block) { * @return true if both block match */ public boolean compareBlockData(BlockData blockData) { - return this.blockData.matches(blockData); + return this.material.equals(blockData.getMaterial()); } /** @@ -108,7 +106,7 @@ public boolean compareBlockData(BlockData blockData) { * @return new Simpleblock */ public SimpleBlock add(Location loc) { - return new SimpleBlock(locX + loc.getBlockX(), locY + loc.getBlockY(), locZ + loc.getBlockZ(), this.blockData); + return new SimpleBlock(locX + loc.getBlockX(), locY + loc.getBlockY(), locZ + loc.getBlockZ(), this.material); } /** @@ -117,7 +115,7 @@ public SimpleBlock add(Location loc) { * @return a new block with a shifted location */ public SimpleBlock add(Vector vect) { - return new SimpleBlock(toVector().add(vect), this.blockData); + return new SimpleBlock(toVector().add(vect), this.material); } /** @@ -126,7 +124,7 @@ public SimpleBlock add(Vector vect) { * @return new block with new subtracted location */ public SimpleBlock subtract(Vector vect) { - return new SimpleBlock(vect.getBlockX() - locX, vect.getBlockY() - locY, vect.getBlockZ() - locZ, this.blockData); + return new SimpleBlock(vect.getBlockX() - locX, vect.getBlockY() - locY, vect.getBlockZ() - locZ, this.material); } /** @@ -143,7 +141,7 @@ public void directSubtract(Vector vect) { * shifts the location of the block without comparing the id */ public SimpleBlock subtractInverted(Location loc) { - return new SimpleBlock(loc.getBlockX() - locX, loc.getBlockY() - locY, loc.getBlockZ() - locZ, this.blockData); + return new SimpleBlock(loc.getBlockX() - locX, loc.getBlockY() - locY, loc.getBlockZ() - locZ, this.material); } @@ -151,7 +149,7 @@ public SimpleBlock subtractInverted(Location loc) { * shifts the location of the block without comparing the id */ public SimpleBlock subtract(Location loc) { - return new SimpleBlock(locX - loc.getBlockX(), locY - loc.getBlockY(), locZ - loc.getBlockZ(), this.blockData); + return new SimpleBlock(locX - loc.getBlockX(), locY - loc.getBlockY(), locZ - loc.getBlockZ(), this.material); } /** From 8fef6ce51f532b9100736e6e3a51dc84e5a421c2 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 12:32:57 +0200 Subject: [PATCH 03/48] Use new library --- cannons-bukkit/pom.xml | 6 +- .../pavlov/cannons/cannon/DesignStorage.java | 276 +++++++++--------- .../pavlov/cannons/container/SimpleBlock.java | 31 +- .../schematic/formats/WorldEditFormat.java | 25 +- 4 files changed, 200 insertions(+), 138 deletions(-) diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 984c603b..17ae786a 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -125,7 +125,7 @@ com.github.Intybyte SchematicLib - 5acc213e0c + f092c09e70 @@ -250,6 +250,10 @@ me.vaan at.pavlov.cannons.shaded.vaan + + com.google.gson + at.pavlov.cannons.shaded.google + diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java index a986f0f0..a4800e28 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java @@ -2,6 +2,7 @@ import at.pavlov.cannons.Cannons; import at.pavlov.cannons.config.Config; +import at.pavlov.cannons.schematic.formats.WorldEditFormat; import at.pavlov.internal.container.DesignFileName; import at.pavlov.cannons.container.ItemHolder; import at.pavlov.cannons.container.SimpleBlock; @@ -17,14 +18,17 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.transform.AffineTransform; -import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.io.Closer; -import com.sk89q.worldedit.world.block.BlockState; import lombok.Getter; -import org.bukkit.Bukkit; +import me.vaan.schematiclib.base.block.BlockKey; +import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.formats.SchematicLoader; +import me.vaan.schematiclib.base.schematic.Schematic; +import me.vaan.schematiclib.file.block.FileBlock; +import me.vaan.schematiclib.file.formats.VaanFormat; +import me.vaan.schematiclib.file.schematic.FileSchematic; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.file.FileConfiguration; @@ -164,14 +168,21 @@ private ArrayList getDesignFiles() { String schematicFile = CannonsUtil.changeExtension(ymlFile, ".schematic"); String schemFile = CannonsUtil.changeExtension(ymlFile, ".schem"); - if (new File(getPath() + schematicFile).isFile()) { - // there is a shematic file and a .yml file - designList.add(new DesignFileName(ymlFile, schematicFile)); - } else if (new File(getPath() + schemFile).isFile()) { - // there is a shematic file and a .yml file - designList.add(new DesignFileName(ymlFile, schemFile)); - } else { - plugin.logSevere(schematicFile + " is missing"); + String vschemFile = CannonsUtil.changeExtension(ymlFile, ".vschem"); + + String[] toCheck = new String[] {schemFile, schematicFile, vschemFile}; + boolean success = false; + for (String entry: toCheck) { + File file = new File(getPath() + entry); + if (file.isFile()) { + designList.add(new DesignFileName(ymlFile, entry)); + success = true; + break; + } + } + + if (!success) { + plugin.logSevere("Schematic is missing for configuration: " + ymlFile); } } } catch (Exception e) { @@ -399,79 +410,78 @@ private Clipboard loadSchematic(String schematicFile) { } } + private static BlockKey bk(BlockData data) { + NamespacedKey key = data.getMaterial().getKey(); + return new BlockKey(key.getNamespace(), key.getKey()); + } + /** * loads the schematic of the config file * @param cannonDesign design of the cannon * @param schematicFile path of the schematic file */ + private static final BlockFace[] HORIZONTALS = new BlockFace[] {BlockFace.EAST, BlockFace.SOUTH, BlockFace.NORTH, BlockFace.WEST}; private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicFile) { long startTime = System.nanoTime(); - - // load schematic with worldedit - Clipboard cc = loadSchematic(schematicFile); - //failed to load schematic - if (cc == null) { - return false; - } + + String schematicPath = getPath() + schematicFile; + File schemFile = new File(schematicPath); // convert all schematic blocks from the config to BaseBlocks so they // can be rotated - BlockData blockIgnore = cannonDesign.getSchematicBlockTypeIgnore(); - BlockData blockMuzzle = cannonDesign.getSchematicBlockTypeMuzzle(); - BlockData blockFiringIndicator = cannonDesign.getSchematicBlockTypeFiringIndicator(); - BlockData blockRotationCenter = cannonDesign.getSchematicBlockTypeRotationCenter(); - BlockData blockChestAndSign = cannonDesign.getSchematicBlockTypeChestAndSign(); - BlockData blockRedstoneTorch = cannonDesign.getSchematicBlockTypeRedstoneTorch(); - BlockData blockRedstoneWireAndRepeater = cannonDesign.getSchematicBlockTypeRedstoneWireAndRepeater(); - BlockData blockRedstoneTrigger = cannonDesign.getSchematicBlockTypeRedstoneTrigger(); - BlockData blockRightClickTrigger = cannonDesign.getSchematicBlockTypeRightClickTrigger(); - BlockData replaceRedstoneTrigger = cannonDesign.getIngameBlockTypeRedstoneTrigger(); - BlockData replaceRightClickTrigger = cannonDesign.getIngameBlockTypeRightClickTrigger(); + BlockData blockIgnore = cannonDesign.getSchematicBlockTypeIgnore(); + BlockData blockMuzzle = cannonDesign.getSchematicBlockTypeMuzzle(); + BlockData blockFiringIndicator = cannonDesign.getSchematicBlockTypeFiringIndicator(); + BlockData blockRotationCenter = cannonDesign.getSchematicBlockTypeRotationCenter(); + BlockData blockChestAndSign = cannonDesign.getSchematicBlockTypeChestAndSign(); + BlockData blockRedstoneTorch = cannonDesign.getSchematicBlockTypeRedstoneTorch(); + BlockData blockRedstoneWireAndRepeater = cannonDesign.getSchematicBlockTypeRedstoneWireAndRepeater(); + BlockData blockRedstoneTrigger = cannonDesign.getSchematicBlockTypeRedstoneTrigger(); + BlockData blockRightClickTrigger = cannonDesign.getSchematicBlockTypeRightClickTrigger(); + BlockData replaceRedstoneTrigger = cannonDesign.getIngameBlockTypeRedstoneTrigger(); + BlockData replaceRightClickTrigger = cannonDesign.getIngameBlockTypeRightClickTrigger(); List blockProtectedList = new ArrayList<>(cannonDesign.getSchematicBlockTypeProtected()); + List blockKeys = blockProtectedList.stream().map(DesignStorage::bk).toList(); - // get facing of the cannon - BlockFace cannonDirection = cannonDesign.getDefaultHorizontalFacing(); - - ClipboardHolder clipboardHolder = new ClipboardHolder(cc); - clipboardHolder.setTransform(new AffineTransform().translate(cc.getMinimumPoint().multiply(-1))); - cc = clipboardHolder.getClipboard(); - - // read out blocks - int width = cc.getDimensions().getBlockX(); - int height = cc.getDimensions().getBlockY(); - int length = cc.getDimensions().getBlockZ(); - - cc.setOrigin(BlockVector3.ZERO); + // get facing of the cannon + BlockFace cannonDirection = cannonDesign.getDefaultHorizontalFacing(); //plugin.logDebug("design: " + schematicFile); - ArrayList schematicList = getSchematic(width, height, length, cc, blockIgnore); + Schematic blocks = getSchematic(schemFile, bk(blockIgnore)); + if (blocks == null) return false; - for (int i = 0; i < 4; i++) { - // create CannonBlocks entry + //todo try string confrontation with match... + int width = blocks.positions().stream().mapToInt(IBlock::x).max().orElse(0) - blocks.positions().stream().mapToInt(IBlock::x).min().orElse(0) + 1; + int height = blocks.positions().stream().mapToInt(IBlock::y).max().orElse(0) - blocks.positions().stream().mapToInt(IBlock::y).min().orElse(0) + 1; + int length = blocks.positions().stream().mapToInt(IBlock::z).max().orElse(0) - blocks.positions().stream().mapToInt(IBlock::z).min().orElse(0) + 1; + + for (int i = 0; i < 4; i++) { + // create CannonBlocks entry CannonBlocks cannonBlocks = new CannonBlocks(); - // to set the muzzle location the maximum and mininum x, y, z values - // of all muzzle blocks have to be found - Vector minMuzzle = new Vector(0, 0, 0); - Vector maxMuzzle = new Vector(0, 0, 0); - boolean firstEntryMuzzle = true; - - // to set the rotation Center maximum and mininum x, y, z values - // of all rotation blocks have to be found - // setting max to the size of the marked area is a good approximation - // if no rotationblock is given - Vector minRotation = new Vector(0, 0, 0); - Vector maxRotation = new Vector(width, height, length); - boolean firstEntryRotation = true; - - for (SimpleBlock sblock : schematicList) { - int x = sblock.getLocX(); - int y = sblock.getLocY(); - int z = sblock.getLocZ(); + // to set the muzzle location the maximum and mininum x, y, z values + // of all muzzle blocks have to be found + Vector minMuzzle = new Vector(0, 0, 0); + Vector maxMuzzle = new Vector(0, 0, 0); + boolean firstEntryMuzzle = true; + + // to set the rotation Center maximum and mininum x, y, z values + // of all rotation blocks have to be found + // setting max to the size of the marked area is a good approximation + // if no rotationblock is given + Vector minRotation = new Vector(0, 0, 0); + Vector maxRotation = new Vector(width, height, length); + boolean firstEntryRotation = true; + + for (IBlock sblock : blocks) { + int x = sblock.x(); + int y = sblock.y(); + int z = sblock.z(); // ############# find the min and max for muzzle blocks so the // cannonball is fired from the middle - if (sblock.compareMaterial(blockMuzzle)) { + BlockKey key = sblock.key(); + if (key.equals(bk(blockMuzzle))) { // reset for the first entry if (firstEntryMuzzle) { firstEntryMuzzle = false; @@ -485,7 +495,7 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, Material.AIR)); } // ############# find the min and max for rotation blocks - else if (sblock.compareMaterial(blockRotationCenter)) { + else if (key.equals(bk(blockRotationCenter))) { // reset for the first entry if (firstEntryRotation) { firstEntryRotation = false; @@ -497,63 +507,63 @@ else if (sblock.compareMaterial(blockRotationCenter)) { } } // ############# redstoneTorch - else if (sblock.compareMaterial(blockRedstoneTorch)) + else if (key.equals(bk(blockRedstoneTorch))) cannonBlocks.addRedstoneTorch(new Vector(x, y, z)); // ############# redstoneWire and Repeater - else if (sblock.compareMaterial(blockRedstoneWireAndRepeater)) + else if (key.equals(bk(blockRedstoneWireAndRepeater))) cannonBlocks.addRedstoneWiresAndRepeater(new SimpleBlock(x, y, z, Material.REPEATER)); // ############# redstoneTrigger - else if (sblock.compareMaterial(blockRedstoneTrigger)) { + else if (key.equals(bk(blockRedstoneTrigger))) { cannonBlocks.addRedstoneTrigger(new Vector(x, y, z)); // buttons or levers are part of the cannon cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRedstoneTrigger)); // this can be a destructible block - if (!isInList(blockProtectedList, sblock.getBlockData())) + if (!isInList(blockKeys, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } // ############# rightClickTrigger - else if (sblock.compareMaterial(blockRightClickTrigger)) { + else if (key.equals(bk(blockRightClickTrigger))) { cannonBlocks.addRightClickTrigger(new Vector(x, y, z)); //can be also a sign - if (sblock.compareMaterial(blockChestAndSign)) + if (key.equals(bk(blockChestAndSign))) // the id does not matter, but the data is important for signs - cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, sblock.getBlockData())); //Material.WALL_SIGN + cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, key)); //Material.WALL_SIGN // firing blocks are also part of the cannon are // part of the cannon cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRightClickTrigger)); // this can be a destructible block - if (!isInList(blockProtectedList, sblock.getBlockData())) + if (!isInList(blockKeys, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } // ############# chests and signs - else if (sblock.compareMaterial(blockChestAndSign)) { + else if (key.equals(bk(blockChestAndSign))) { // the id does not matter, but the data is important for signs - cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, sblock.getBlockData())); //Material.WALL_SIGN + cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, key)); //Material.WALL_SIGN } // ############# loading Interface is a cannonblock that is non of // the previous blocks else { // all remaining blocks are loading interface or cannonBlocks cannonBlocks.addBarrel(new Vector(x, y, z)); - cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, sblock.getBlockData())); + cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, key)); // this can be a destructible block - if (!isInList(blockProtectedList, sblock.getBlockData())) + if (!isInList(blockKeys, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } // ############# firingIndicator // can be everywhere on the cannon - if (sblock.compareMaterial(blockFiringIndicator)) + if (key.equals(bk(blockFiringIndicator))) cannonBlocks.addFiringIndicator(new Vector(x, y, z)); } - // calculate the muzzle location - maxMuzzle.add(new Vector(1, 1, 1)); - cannonBlocks.setMuzzle(maxMuzzle.add(minMuzzle).multiply(0.5)); + // calculate the muzzle location + maxMuzzle.add(new Vector(1, 1, 1)); + cannonBlocks.setMuzzle(maxMuzzle.add(minMuzzle).multiply(0.5)); - // calculate the rotation Center - maxRotation.add(new Vector(1, 1, 1)); - cannonBlocks.setRotationCenter(maxRotation.add(maxRotation).multiply(0.5)); + // calculate the rotation Center + maxRotation.add(new Vector(1, 1, 1)); + cannonBlocks.setRotationCenter(maxRotation.add(maxRotation).multiply(0.5)); //set the muzzle location Vector compensation = new Vector(cannonBlocks.getMuzzle().getBlockX(), cannonBlocks.getMuzzle().getBlockY(), cannonBlocks.getMuzzle().getBlockZ()); @@ -579,33 +589,41 @@ else if (sblock.compareMaterial(blockChestAndSign)) { cannonBlocks.getMuzzle().subtract(compensation); cannonBlocks.getRotationCenter().subtract(compensation); - // add blocks to the HashMap - cannonDesign.putCannonBlockMap(cannonDirection, cannonBlocks); - - //rotate blocks for the next iteration - blockIgnore = CannonsUtil.roateBlockFacingClockwise(blockIgnore); - blockMuzzle = CannonsUtil.roateBlockFacingClockwise(blockMuzzle); - blockFiringIndicator = CannonsUtil.roateBlockFacingClockwise(blockFiringIndicator); - blockRotationCenter = CannonsUtil.roateBlockFacingClockwise(blockRotationCenter); - blockChestAndSign = CannonsUtil.roateBlockFacingClockwise(blockChestAndSign); - blockRedstoneTorch = CannonsUtil.roateBlockFacingClockwise(blockRedstoneTorch); - blockRedstoneTrigger = CannonsUtil.roateBlockFacingClockwise(blockRedstoneTrigger); - blockRightClickTrigger = CannonsUtil.roateBlockFacingClockwise(blockRightClickTrigger); - replaceRedstoneTrigger = CannonsUtil.roateBlockFacingClockwise(replaceRedstoneTrigger); - replaceRightClickTrigger = CannonsUtil.roateBlockFacingClockwise(replaceRightClickTrigger); - - blockProtectedList = blockProtectedList.stream().map(CannonsUtil::roateBlockFacingClockwise).toList(); - - //rotate schematic blocks - for (SimpleBlock simpleBlock : schematicList){ - simpleBlock.rotate90(); - } + // add blocks to the HashMap + cannonDesign.putCannonBlockMap(cannonDirection, cannonBlocks); + + //rotate blocks for the next iteration + blockIgnore = CannonsUtil.roateBlockFacingClockwise(blockIgnore); + blockMuzzle = CannonsUtil.roateBlockFacingClockwise(blockMuzzle); + blockFiringIndicator = CannonsUtil.roateBlockFacingClockwise(blockFiringIndicator); + blockRotationCenter = CannonsUtil.roateBlockFacingClockwise(blockRotationCenter); + blockChestAndSign = CannonsUtil.roateBlockFacingClockwise(blockChestAndSign); + blockRedstoneTorch = CannonsUtil.roateBlockFacingClockwise(blockRedstoneTorch); + blockRedstoneTrigger = CannonsUtil.roateBlockFacingClockwise(blockRedstoneTrigger); + blockRightClickTrigger = CannonsUtil.roateBlockFacingClockwise(blockRightClickTrigger); + replaceRedstoneTrigger = CannonsUtil.roateBlockFacingClockwise(replaceRedstoneTrigger); + replaceRightClickTrigger = CannonsUtil.roateBlockFacingClockwise(replaceRightClickTrigger); + + blockProtectedList = blockProtectedList.stream().map(CannonsUtil::roateBlockFacingClockwise).toList(); + + //rotate schematic blocks + ArrayList newList = new ArrayList<>(); + for (IBlock simpleBlock : blocks){ + newList.add( + new FileBlock( + -simpleBlock.z(), + simpleBlock.y(), + simpleBlock.x(), + simpleBlock.key() + ) + ); + } - //rotate cannonDirection - cannonDirection = CannonsUtil.roatateFace(cannonDirection); + blocks = new FileSchematic(newList); + cannonDirection = CannonsUtil.roatateFace(cannonDirection); + } - } plugin.logDebug("Time to load designs: " + new DecimalFormat("0.00").format((System.nanoTime() - startTime)/1000000.0) + "ms"); return true; @@ -654,13 +672,13 @@ private void copyFile(String fileName) } } - private boolean isInList(List list, BlockData block) + private boolean isInList(List list, T block) { if (block == null) return true; - for (BlockData listBlock : list) + for (T listBlock : list) { - if (listBlock != null && listBlock.getMaterial().equals(block.getMaterial())) + if (listBlock != null && listBlock.equals(block)) return true; } return false; @@ -724,26 +742,22 @@ public boolean isCannonBlockMaterial(Material material) { return material != Material.AIR && cannonBlockMaterials.contains(material); } - private ArrayList getSchematic(int width, int height, int length, Clipboard cc, BlockData blockIgnore) { - ArrayList schematiclist = new ArrayList<>(); - for (int x = 0; x < width; ++x) { - for (int y = 0; y < height; ++y) { - for (int z = 0; z < length; ++z) { - BlockVector3 pt = BlockVector3.at(x, y, z); - BlockState blockState = cc.getBlock(pt.add(cc.getMinimumPoint())); - //plugin.logDebug("blockstate: " + blockState.getAsString()); - - BlockData block = Bukkit.getServer().createBlockData(blockState.getAsString()); + private static final SchematicLoader[] loaders = new SchematicLoader[] { + new WorldEditFormat(), + new VaanFormat() + }; + private Schematic getSchematic(File file, BlockKey blockIgnore) { + for (SchematicLoader loader : loaders) { + try { + Schematic schm = loader.load(file); + List list = schm.positions().stream().filter(it -> !it.key().equals(blockIgnore) && !it.key().key().equals("air")).toList(); + return new FileSchematic(list); + } catch (Throwable ignored) {} + } - // ignore if block is AIR or the IgnoreBlock type - if (!block.getMaterial().equals(Material.AIR) && !block.matches(blockIgnore)) { - schematiclist.add(new SimpleBlock(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ(), block)); - } - } - } - } - return schematiclist; + plugin.logSevere("Couldn't load " + file.getPath()); + return null; } } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/container/SimpleBlock.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/container/SimpleBlock.java index 3dd1a8ca..9bf4e211 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/container/SimpleBlock.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/container/SimpleBlock.java @@ -4,8 +4,12 @@ import lombok.Getter; import lombok.Setter; import lombok.ToString; +import me.vaan.schematiclib.base.block.BlockKey; +import me.vaan.schematiclib.base.block.IBlock; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; @@ -14,7 +18,7 @@ @Setter @Getter @ToString -public class SimpleBlock { +public class SimpleBlock implements IBlock { private int locX; private int locY; private int locZ; @@ -46,6 +50,10 @@ public SimpleBlock(Location loc, Material material) { this(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), material); } + public SimpleBlock(int x, int y, int z, BlockKey key) { + this(x, y, z, Registry.MATERIAL.get(new NamespacedKey(key.namespace(), key.key()))); + } + /** * to location with offset @@ -167,4 +175,25 @@ public void rotate90() { public Vector toVector() { return new Vector(locX, locY, locZ); } + + @Override + public int x() { + return locX; + } + + @Override + public int y() { + return locY; + } + + @Override + public int z() { + return locZ; + } + + @Override + public BlockKey key() { + NamespacedKey key = material.getKey(); + return new BlockKey(key.getNamespace(), key.getKey()); + } } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java index 4a5e9c60..55d5d727 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java @@ -7,7 +7,8 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.world.block.BlockState; import me.vaan.schematiclib.base.block.IBlock; @@ -29,13 +30,27 @@ public Schematic load(File file) throws Throwable { Clipboard cc = loadSchematic(file); if (cc == null) throw new FileExceptionUnknown("Schematic not found"); - Region region = cc.getRegion(); + ClipboardHolder clipboardHolder = new ClipboardHolder(cc); + clipboardHolder.setTransform(new AffineTransform().translate(cc.getMinimumPoint().multiply(-1))); + Clipboard transformedCC = clipboardHolder.getClipboard(); + + cc.setOrigin(BlockVector3.ZERO); List positions = new ArrayList<>(); - for (BlockVector3 pos : region) { - BlockState state = cc.getBlock(pos); - positions.add(new WorldEditBlock(state, pos)); + int width = transformedCC.getDimensions().getBlockX(); + int height = transformedCC.getDimensions().getBlockY(); + int length = transformedCC.getDimensions().getBlockZ(); + + for (int x = 0; x < width; ++x) { + for (int y = 0; y < height; ++y) { + for (int z = 0; z < length; ++z) { + BlockVector3 pt = BlockVector3.at(x, y, z); + BlockState blockState = cc.getBlock(pt.add(cc.getMinimumPoint())); + + positions.add(new WorldEditBlock(blockState, pt)); + } + } } return new FileSchematic(positions); From 48e8e394da30e4fed2cec4ab9568da8e45b000c4 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 12:41:39 +0200 Subject: [PATCH 04/48] This can be static public --- .../src/main/java/at/pavlov/cannons/cannon/DesignStorage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java index a4800e28..16f6354c 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java @@ -684,7 +684,7 @@ private boolean isInList(List list, T block) return false; } - private String getPath() + public static String getPath() { // Directory path here return "plugins/Cannons/designs/"; From 99a311a480bff2ccadfcc88b97aec6a1258db957 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 13:43:04 +0200 Subject: [PATCH 05/48] Fixes --- cannons-bukkit/pom.xml | 2 +- .../pavlov/cannons/cannon/DesignStorage.java | 23 +------------------ .../schematic/formats/WorldEditFormat.java | 6 +---- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 17ae786a..a9bf1850 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -125,7 +125,7 @@ com.github.Intybyte SchematicLib - f092c09e70 + fdc507c3c0 diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java index 16f6354c..93540e61 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java @@ -388,28 +388,6 @@ private void loadDesignYml(CannonDesign cannonDesign, String ymlFile) cannonDesign.setSchematicBlockTypeProtected(ParseUtils.toBlockDataList(cannonDesignConfig.getStringList("constructionBlocks.protectedBlocks"))); } - private Clipboard loadSchematic(String schematicFile) { - String schematicPath = getPath() + schematicFile; - File f = new File(schematicPath); - ClipboardFormat format = ClipboardFormats.findByFile(f); - - if(format == null) { - plugin.logSevere("Error while loading schematic " + schematicPath + " : Format not found"); - return null; - } - - try (Closer closer = Closer.create()) { - FileInputStream fis = closer.register(new FileInputStream(f)); - BufferedInputStream bis = closer.register(new BufferedInputStream(fis)); - ClipboardReader reader = closer.register(format.getReader(bis)); - - return reader.read(); - } catch (IOException e) { - plugin.logSevere("Error while loading schematic " + schematicPath + " : IO Error"); - return null; - } - } - private static BlockKey bk(BlockData data) { NamespacedKey key = data.getMaterial().getKey(); return new BlockKey(key.getNamespace(), key.getKey()); @@ -752,6 +730,7 @@ private Schematic getSchematic(File file, BlockKey blockIgnore) { for (SchematicLoader loader : loaders) { try { Schematic schm = loader.load(file); + if (schm == null) continue; List list = schm.positions().stream().filter(it -> !it.key().equals(blockIgnore) && !it.key().key().equals("air")).toList(); return new FileSchematic(list); } catch (Throwable ignored) {} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java index 55d5d727..d6be6d86 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/formats/WorldEditFormat.java @@ -56,11 +56,10 @@ public Schematic load(File file) throws Throwable { return new FileSchematic(positions); } - private Clipboard loadSchematic(File schematicFile) { + private Clipboard loadSchematic(File schematicFile) throws IOException { ClipboardFormat format = ClipboardFormats.findByFile(schematicFile); if(format == null) { - Cannons.getPlugin().logSevere("Error while loading schematic " + schematicFile.getPath() + " : Format not found"); return null; } @@ -70,9 +69,6 @@ private Clipboard loadSchematic(File schematicFile) { ClipboardReader reader = closer.register(format.getReader(bis)); return reader.read(); - } catch (IOException e) { - Cannons.getPlugin().logSevere("Error while loading schematic " + schematicFile.getPath() + " : IO Error"); - return null; } } } From 5ba859147c61f30c9f33c961e4e3bbc23bbb894d Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 13:43:10 +0200 Subject: [PATCH 06/48] New commands --- .../at/pavlov/cannons/commands/Commands.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java index 6dafbdc7..1441b728 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java @@ -18,11 +18,14 @@ import at.pavlov.cannons.projectile.Projectile; import at.pavlov.cannons.projectile.ProjectileStorage; import at.pavlov.cannons.projectile.definitions.ProjectileDefinitionLoader; +import at.pavlov.cannons.schematic.world.SchematicWorldProcessorImpl; import at.pavlov.cannons.utils.CannonSelector; import at.pavlov.cannons.utils.CannonsUtil; import at.pavlov.cannons.utils.StringUtils; import co.aikar.commands.BaseCommand; import co.aikar.commands.annotation.*; +import me.vaan.schematiclib.base.schematic.Schematic; +import me.vaan.schematiclib.file.formats.VaanFormat; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; @@ -31,6 +34,7 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.PluginDescriptionFile; +import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -315,6 +319,33 @@ public static void onObserver(Player player, String[] args) { //sendMessage(sender, ChatColor.RED + "Usage '/cannons observer' or '/cannons observer ' or '/cannons observer '"); } + @Subcommand("schematic") + @CommandPermission("cannons.admin.reload") + public class onSchematic extends BaseCommand { + private static final SchematicWorldProcessorImpl processor = new SchematicWorldProcessorImpl(); + + @Default + public static void help(Player player) { + sendMessage(player, ChatColor.RED + "Usage '/cannons schematic save '"); + } + + @Subcommand("save") + public static void save(Player player, int xA, int yA, int zA, int xB, int yB, int zB, String name) { + String fullName = name + ".vschem"; + Schematic schematic = processor.schematicOf(xA, yA, zA, xB, yB, zB, player.getWorld().getUID()); + + String fullPath = DesignStorage.getPath() + fullName; + File file = new File(fullPath); + + VaanFormat format = new VaanFormat(); + try { + format.save(file, schematic); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + } + @Subcommand("whitelist") @CommandPermission("cannons.player.whitelist") public class onWhitelist extends BaseCommand { From e0a0f9e68d2327cb5a451ec8d80871d2da2b1918 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 15:48:30 +0200 Subject: [PATCH 07/48] Use new max and min --- .../java/at/pavlov/cannons/cannon/DesignStorage.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java index 93540e61..77406705 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java @@ -428,10 +428,11 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF Schematic blocks = getSchematic(schemFile, bk(blockIgnore)); if (blocks == null) return false; - //todo try string confrontation with match... - int width = blocks.positions().stream().mapToInt(IBlock::x).max().orElse(0) - blocks.positions().stream().mapToInt(IBlock::x).min().orElse(0) + 1; - int height = blocks.positions().stream().mapToInt(IBlock::y).max().orElse(0) - blocks.positions().stream().mapToInt(IBlock::y).min().orElse(0) + 1; - int length = blocks.positions().stream().mapToInt(IBlock::z).max().orElse(0) - blocks.positions().stream().mapToInt(IBlock::z).min().orElse(0) + 1; + ICoord max = blocks.getMax(); + ICoord min = blocks.getMin(); + int width = max.x() - min.x() + 1; + int height = max.y() - min.y() + 1; + int length = max.z() - min.z() + 1; for (int i = 0; i < 4; i++) { // create CannonBlocks entry From 7d4253adc34787d124e6ae28f0c872d906a09d01 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 17:36:32 +0200 Subject: [PATCH 08/48] Turn SchematicWorldProcessorImpl into a singleton --- .../src/main/java/at/pavlov/cannons/commands/Commands.java | 3 +-- .../cannons/schematic/world/SchematicWorldProcessorImpl.java | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java index 1441b728..213db7ab 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java @@ -322,7 +322,6 @@ public static void onObserver(Player player, String[] args) { @Subcommand("schematic") @CommandPermission("cannons.admin.reload") public class onSchematic extends BaseCommand { - private static final SchematicWorldProcessorImpl processor = new SchematicWorldProcessorImpl(); @Default public static void help(Player player) { @@ -332,7 +331,7 @@ public static void help(Player player) { @Subcommand("save") public static void save(Player player, int xA, int yA, int zA, int xB, int yB, int zB, String name) { String fullName = name + ".vschem"; - Schematic schematic = processor.schematicOf(xA, yA, zA, xB, yB, zB, player.getWorld().getUID()); + Schematic schematic = SchematicWorldProcessorImpl.getProcessor().schematicOf(xA, yA, zA, xB, yB, zB, player.getWorld().getUID()); String fullPath = DesignStorage.getPath() + fullName; File file = new File(fullPath); diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java index dda61483..4a844945 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java @@ -1,13 +1,16 @@ package at.pavlov.cannons.schematic.world; import at.pavlov.cannons.schematic.namespace.MinecraftNamespaceHandler; +import lombok.Getter; import me.vaan.schematiclib.base.namespace.NamespaceRegistry; import me.vaan.schematiclib.base.world.SchematicWorldProcessor; public class SchematicWorldProcessorImpl implements SchematicWorldProcessor { + @Getter + private static final SchematicWorldProcessorImpl processor = new SchematicWorldProcessorImpl(); private final NamespaceRegistry registry; - public SchematicWorldProcessorImpl() { + private SchematicWorldProcessorImpl() { this.registry = new NamespaceRegistry("minecraft", new MinecraftNamespaceHandler()); } From 75c1ad63da6454fd3f7e8c718a7fd346aad3efed Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 17:38:12 +0200 Subject: [PATCH 09/48] Use new schematic system to create & check cannons --- .../pavlov/cannons/cannon/CannonDesign.java | 28 ++++-- .../pavlov/cannons/cannon/CannonManager.java | 36 ++++---- .../pavlov/cannons/cannon/DesignStorage.java | 87 ++++++++++++------- 3 files changed, 99 insertions(+), 52 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java index 65eb8260..8a8294e6 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java @@ -8,8 +8,11 @@ import at.pavlov.cannons.projectile.Projectile; import at.pavlov.internal.Key; import lombok.Data; +import me.vaan.schematiclib.base.schematic.Schematic; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; @@ -192,6 +195,7 @@ //cannon design block lists for every direction (NORTH, EAST, SOUTH, WEST) private final HashMap cannonBlockMap = new HashMap<>(); + private final HashMap schematicMap = new HashMap<>(); private final EnumSet allowedMaterials = EnumSet.noneOf(Material.class); @@ -552,13 +556,25 @@ public void setRotatable(boolean isRotatable) } - public void putCannonBlockMap(BlockFace cannonDirection, CannonBlocks blocks) { - for (var block : blocks.getAllCannonBlocks()) { - allowedMaterials.add(block.getBlockData().getMaterial()); - } + public void putCannonBlockMap(BlockFace cannonDirection, CannonBlocks blocks) { + for (var block : blocks.getAllCannonBlocks()) { + allowedMaterials.add(block.getBlockData().getMaterial()); + } - cannonBlockMap.put(cannonDirection, blocks); - } + cannonBlockMap.put(cannonDirection, blocks); + } + + public void putSchematicMap(BlockFace cannonDirection, Schematic blocks) { + blocks.forEach(b -> { + Material m = Registry.MATERIAL.get( + new NamespacedKey(b.key().namespace(), b.key().key()) + ); + + allowedMaterials.add(m); + }); + + schematicMap.put(cannonDirection, blocks); + } public boolean isAllowedMaterial(Material m) { return allowedMaterials.contains(m); diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java index af44a88e..67a2d52a 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java @@ -16,9 +16,13 @@ import at.pavlov.cannons.dao.wrappers.RemoveTaskWrapper; import at.pavlov.cannons.exchange.BExchanger; import at.pavlov.cannons.exchange.EmptyExchanger; +import at.pavlov.cannons.schematic.world.SchematicWorldProcessorImpl; import at.pavlov.cannons.utils.SoundUtils; import com.google.common.base.Preconditions; import lombok.Getter; +import me.vaan.schematiclib.base.schematic.OffsetSchematic; +import me.vaan.schematiclib.base.schematic.OffsetSchematicImpl; +import me.vaan.schematiclib.base.schematic.Schematic; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; @@ -658,6 +662,7 @@ private Cannon checkCannon(Location cannonBlock, UUID owner) { return null; } + Schematic schem = cannonDesign.getSchematicMap().get(cannonDirection); for (SimpleBlock designBlock : designBlockList) { // compare blocks if (!designBlock.compareMaterial(blockData)) { @@ -667,21 +672,22 @@ private Cannon checkCannon(Location cannonBlock, UUID owner) { // this block is same as in the design, get the offset Vector offset = designBlock.subtractInverted(cannonBlock).toVector(); - // check all other blocks of the cannon - boolean isCannon = true; - - for (SimpleBlock checkBlocks : designBlockList) { - if (!checkBlocks.compareMaterial(world, offset)) { - // if the block does not match this is not the - // right one - isCannon = false; - break; - } - } - - // this is a cannon - if (isCannon) { - return new Cannon(cannonDesign, world.getUID(), offset, cannonDirection, owner); + OffsetSchematic offsetSchematic = new OffsetSchematicImpl( + offset.getBlockX(), + offset.getBlockY(), + offset.getBlockZ(), + schem.positions() + ); + + boolean matches = SchematicWorldProcessorImpl.getProcessor().matches(offsetSchematic, cannonBlock.getWorld().getUID()); + if (matches) { + return new Cannon( + cannonDesign, + world.getUID(), + offset, + cannonDirection, + owner + ); } } } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java index 77406705..a9acbc7b 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java @@ -22,9 +22,11 @@ import lombok.Getter; import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.block.ICoord; import me.vaan.schematiclib.base.formats.SchematicLoader; import me.vaan.schematiclib.base.schematic.Schematic; import me.vaan.schematiclib.file.block.FileBlock; +import me.vaan.schematiclib.file.block.FileCoord; import me.vaan.schematiclib.file.formats.VaanFormat; import me.vaan.schematiclib.file.schematic.FileSchematic; import org.bukkit.Material; @@ -437,6 +439,7 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF for (int i = 0; i < 4; i++) { // create CannonBlocks entry CannonBlocks cannonBlocks = new CannonBlocks(); + List filteredSchematic = new ArrayList<>(); // to set the muzzle location the maximum and mininum x, y, z values // of all muzzle blocks have to be found @@ -472,6 +475,7 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF } //muzzle blocks need to be air - else the projectile would spawn in a block cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, Material.AIR)); + filteredSchematic.add(new FileBlock(x, y, z, BlockKey.mc("air"))); } // ############# find the min and max for rotation blocks else if (key.equals(bk(blockRotationCenter))) { @@ -486,50 +490,58 @@ else if (key.equals(bk(blockRotationCenter))) { } } // ############# redstoneTorch - else if (key.equals(bk(blockRedstoneTorch))) + else if (key.equals(bk(blockRedstoneTorch))) { cannonBlocks.addRedstoneTorch(new Vector(x, y, z)); + } // ############# redstoneWire and Repeater - else if (key.equals(bk(blockRedstoneWireAndRepeater))) + else if (key.equals(bk(blockRedstoneWireAndRepeater))) { cannonBlocks.addRedstoneWiresAndRepeater(new SimpleBlock(x, y, z, Material.REPEATER)); - // ############# redstoneTrigger - else if (key.equals(bk(blockRedstoneTrigger))) { - cannonBlocks.addRedstoneTrigger(new Vector(x, y, z)); - // buttons or levers are part of the cannon - cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRedstoneTrigger)); - // this can be a destructible block - if (!isInList(blockKeys, key)) - cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } - // ############# rightClickTrigger - else if (key.equals(bk(blockRightClickTrigger))) { - cannonBlocks.addRightClickTrigger(new Vector(x, y, z)); - //can be also a sign - if (key.equals(bk(blockChestAndSign))) + // ############# redstoneTrigger + else if (!key.equals(bk(blockRedstoneTrigger))) { + if (key.equals(bk(blockRightClickTrigger))) { + cannonBlocks.addRightClickTrigger(new Vector(x, y, z)); + //can be also a sign + if (key.equals(bk(blockChestAndSign))) + // the id does not matter, but the data is important for signs + cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, key)); //Material.WALL_SIGN + // firing blocks are also part of the cannon are + // part of the cannon + cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRightClickTrigger)); + filteredSchematic.add(new FileBlock(x, y, z, bk(replaceRightClickTrigger))); + // this can be a destructible block + if (!isInList(blockKeys, key)) + cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); + } + // ############# chests and signs + else if (key.equals(bk(blockChestAndSign))) { // the id does not matter, but the data is important for signs cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, key)); //Material.WALL_SIGN - // firing blocks are also part of the cannon are - // part of the cannon - cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRightClickTrigger)); - // this can be a destructible block - if (!isInList(blockKeys, key)) - cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); - } - // ############# chests and signs - else if (key.equals(bk(blockChestAndSign))) { - // the id does not matter, but the data is important for signs - cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, key)); //Material.WALL_SIGN + } + // ############# loading Interface is a cannonblock that is non of + // the previous blocks + else { + // all remaining blocks are loading interface or cannonBlocks + cannonBlocks.addBarrel(new Vector(x, y, z)); + cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, key)); + filteredSchematic.add(new FileBlock(x, y, z, key)); + // this can be a destructible block + if (!isInList(blockKeys, key)) + cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); + } } - // ############# loading Interface is a cannonblock that is non of - // the previous blocks + // ############# rightClickTrigger else { - // all remaining blocks are loading interface or cannonBlocks - cannonBlocks.addBarrel(new Vector(x, y, z)); - cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, key)); + cannonBlocks.addRedstoneTrigger(new Vector(x, y, z)); + // buttons or levers are part of the cannon + cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRedstoneTrigger)); + filteredSchematic.add(new FileBlock(x, y, z, bk(replaceRedstoneTrigger))); // this can be a destructible block if (!isInList(blockKeys, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } + // ############# firingIndicator // can be everywhere on the cannon if (key.equals(bk(blockFiringIndicator))) @@ -547,6 +559,18 @@ else if (key.equals(bk(blockChestAndSign))) { //set the muzzle location Vector compensation = new Vector(cannonBlocks.getMuzzle().getBlockX(), cannonBlocks.getMuzzle().getBlockY(), cannonBlocks.getMuzzle().getBlockZ()); + List actualSchematic = new ArrayList<>(); + for (IBlock iblock : filteredSchematic) + actualSchematic.add( + iblock.add( + new FileCoord( + -compensation.getBlockX(), + -compensation.getBlockY(), + -compensation.getBlockZ() + ) + ) + ); + for (SimpleBlock block : cannonBlocks.getAllCannonBlocks()) block.directSubtract(compensation); for (Vector block : cannonBlocks.getBarrelBlocks()) @@ -570,6 +594,7 @@ else if (key.equals(bk(blockChestAndSign))) { // add blocks to the HashMap cannonDesign.putCannonBlockMap(cannonDirection, cannonBlocks); + cannonDesign.putSchematicMap(cannonDirection, new FileSchematic(actualSchematic)); //rotate blocks for the next iteration blockIgnore = CannonsUtil.roateBlockFacingClockwise(blockIgnore); From 7ba84404e1d2c2aaf14c4430b444dab751e8b6f6 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 19:09:10 +0200 Subject: [PATCH 10/48] More detailed name --- .../main/java/at/pavlov/cannons/cannon/DesignStorage.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java index a9acbc7b..7ed3b128 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java @@ -421,7 +421,7 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF BlockData replaceRedstoneTrigger = cannonDesign.getIngameBlockTypeRedstoneTrigger(); BlockData replaceRightClickTrigger = cannonDesign.getIngameBlockTypeRightClickTrigger(); List blockProtectedList = new ArrayList<>(cannonDesign.getSchematicBlockTypeProtected()); - List blockKeys = blockProtectedList.stream().map(DesignStorage::bk).toList(); + List keysBlocksProtected = blockProtectedList.stream().map(DesignStorage::bk).toList(); // get facing of the cannon BlockFace cannonDirection = cannonDesign.getDefaultHorizontalFacing(); @@ -510,7 +510,7 @@ else if (!key.equals(bk(blockRedstoneTrigger))) { cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRightClickTrigger)); filteredSchematic.add(new FileBlock(x, y, z, bk(replaceRightClickTrigger))); // this can be a destructible block - if (!isInList(blockKeys, key)) + if (!isInList(keysBlocksProtected, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } // ############# chests and signs @@ -526,7 +526,7 @@ else if (key.equals(bk(blockChestAndSign))) { cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, key)); filteredSchematic.add(new FileBlock(x, y, z, key)); // this can be a destructible block - if (!isInList(blockKeys, key)) + if (!isInList(keysBlocksProtected, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } } @@ -537,7 +537,7 @@ else if (key.equals(bk(blockChestAndSign))) { cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRedstoneTrigger)); filteredSchematic.add(new FileBlock(x, y, z, bk(replaceRedstoneTrigger))); // this can be a destructible block - if (!isInList(blockKeys, key)) + if (!isInList(keysBlocksProtected, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } From 0f1d260c7b630b5f66e2e60094fb00d5c944fb76 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 19:09:24 +0200 Subject: [PATCH 11/48] Get the block properly --- .../pavlov/cannons/cannon/CannonManager.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java index 67a2d52a..d4c2d91e 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java @@ -20,6 +20,7 @@ import at.pavlov.cannons.utils.SoundUtils; import com.google.common.base.Preconditions; import lombok.Getter; +import me.vaan.schematiclib.base.block.IBlock; import me.vaan.schematiclib.base.schematic.OffsetSchematic; import me.vaan.schematiclib.base.schematic.OffsetSchematicImpl; import me.vaan.schematiclib.base.schematic.Schematic; @@ -29,7 +30,6 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; @@ -642,7 +642,11 @@ public static Cannon getCannon(UUID uid) { private Cannon checkCannon(Location cannonBlock, UUID owner) { // is this block material used for a cannon design Block block = cannonBlock.getBlock(); - BlockData blockData = cannonBlock.getBlock().getBlockData(); + IBlock blockStuff = SchematicWorldProcessorImpl + .getProcessor() + .registry() + .getBlock(block.getX(), block.getY(), block.getZ(), block.getWorld().getUID()); + if (!isValidCannonBlock(block)) return null; @@ -663,14 +667,18 @@ private Cannon checkCannon(Location cannonBlock, UUID owner) { } Schematic schem = cannonDesign.getSchematicMap().get(cannonDirection); - for (SimpleBlock designBlock : designBlockList) { + for (IBlock designBlock : schem) { // compare blocks - if (!designBlock.compareMaterial(blockData)) { + if (!designBlock.key().equals(blockStuff.key())) { continue; } // this block is same as in the design, get the offset - Vector offset = designBlock.subtractInverted(cannonBlock).toVector(); + Vector offset = new Vector( + cannonBlock.getBlockX() - designBlock.x(), + cannonBlock.getBlockY() - designBlock.y(), + cannonBlock.getBlockZ() - designBlock.z() + ); OffsetSchematic offsetSchematic = new OffsetSchematicImpl( offset.getBlockX(), @@ -679,7 +687,7 @@ private Cannon checkCannon(Location cannonBlock, UUID owner) { schem.positions() ); - boolean matches = SchematicWorldProcessorImpl.getProcessor().matches(offsetSchematic, cannonBlock.getWorld().getUID()); + boolean matches = SchematicWorldProcessorImpl.getProcessor().matches(offsetSchematic, world.getUID()); if (matches) { return new Cannon( cannonDesign, From 0ee49f23e8bba2bd0534d86004084dbf08c87f7d Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 20:47:28 +0200 Subject: [PATCH 12/48] Add method to register namespaces --- .../schematic/world/SchematicWorldProcessorImpl.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java index 4a844945..25edf4b6 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java @@ -2,6 +2,7 @@ import at.pavlov.cannons.schematic.namespace.MinecraftNamespaceHandler; import lombok.Getter; +import me.vaan.schematiclib.base.namespace.NamespaceHandler; import me.vaan.schematiclib.base.namespace.NamespaceRegistry; import me.vaan.schematiclib.base.world.SchematicWorldProcessor; @@ -18,5 +19,15 @@ private SchematicWorldProcessorImpl() { public NamespaceRegistry registry() { return registry; } + + public void registerReflectionNamespace(String namespace, String classToFind, NamespaceHandler handler) { + try { + Class.forName(classToFind); + } catch (Exception e) { + return; + } + + registry.registerNamespaceHandler(namespace, handler); + } } From 758419235eb17fb89fcedc6d0406328bd1feaa6d Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 22 Sep 2025 22:01:36 +0200 Subject: [PATCH 13/48] Update SchematicLib and add destroy to MinecraftNamespaceHandler --- cannons-bukkit/pom.xml | 11 ++++++++++- .../namespace/MinecraftNamespaceHandler.java | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index a9bf1850..36b926e7 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -125,7 +125,7 @@ com.github.Intybyte SchematicLib - fdc507c3c0 + 7158d35884 @@ -154,6 +154,15 @@ provided + + + com.github.Slimefun + Slimefun4 + RC-37 + provided + + + org.junit.jupiter diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java index cefc32c5..c8cced03 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java @@ -8,6 +8,7 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.bukkit.event.block.BlockBreakEvent; import java.util.UUID; @@ -29,4 +30,13 @@ public IBlock get(int x, int y, int z, UUID uuid) { Bukkit.getWorld(uuid).getBlockAt(x, y, z) ); } + + @Override + public void destroy(IBlock iBlock, UUID uuid) { + Bukkit.getWorld(uuid).getBlockAt( + iBlock.x(), + iBlock.y(), + iBlock.z() + ).setType(Material.AIR); + } } From f3cd61e4a49ded06660ede06bfac5e9f28f4f076 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 23 Sep 2025 10:03:04 +0200 Subject: [PATCH 14/48] Add breakNaturally --- cannons-bukkit/pom.xml | 2 +- .../schematic/namespace/MinecraftNamespaceHandler.java | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 36b926e7..157e5445 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -125,7 +125,7 @@ com.github.Intybyte SchematicLib - 7158d35884 + ac11044435 diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java index c8cced03..1df166c7 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java @@ -8,7 +8,6 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; -import org.bukkit.event.block.BlockBreakEvent; import java.util.UUID; @@ -39,4 +38,13 @@ public void destroy(IBlock iBlock, UUID uuid) { iBlock.z() ).setType(Material.AIR); } + + @Override + public void breakNaturally(IBlock iBlock, UUID uuid) { + Bukkit.getWorld(uuid).getBlockAt( + iBlock.x(), + iBlock.y(), + iBlock.z() + ).breakNaturally(); + } } From 2b2af73a94f2390c1985e2183bdddd6052eb7429 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 23 Sep 2025 10:59:25 +0200 Subject: [PATCH 15/48] Use Schematic when needed --- cannons-bukkit/pom.xml | 2 +- .../java/at/pavlov/cannons/cannon/Cannon.java | 89 +++++++++++-------- .../pavlov/cannons/cannon/CannonDesign.java | 2 +- .../cannons/schematic/block/BlockImpl.java | 2 + .../namespace/MinecraftNamespaceHandler.java | 7 ++ .../world/SchematicWorldProcessorImpl.java | 12 ++- 6 files changed, 73 insertions(+), 41 deletions(-) diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 157e5445..34c48077 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -125,7 +125,7 @@ com.github.Intybyte SchematicLib - ac11044435 + 7e2dbdc1bf diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java index 8077aeff..2e1299d2 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java @@ -25,6 +25,7 @@ import at.pavlov.cannons.interfaces.functionalities.Rotational; import at.pavlov.cannons.projectile.Projectile; import at.pavlov.cannons.projectile.ProjectileStorage; +import at.pavlov.cannons.schematic.world.SchematicWorldProcessorImpl; import at.pavlov.cannons.utils.CannonsUtil; import at.pavlov.cannons.utils.InventoryManagement; import at.pavlov.cannons.utils.SoundUtils; @@ -32,6 +33,10 @@ import com.google.common.base.Preconditions; import lombok.Getter; import lombok.Setter; +import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.schematic.OffsetSchematic; +import me.vaan.schematiclib.base.schematic.OffsetSchematicImpl; +import me.vaan.schematiclib.base.schematic.Schematic; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Effect; @@ -130,7 +135,7 @@ public Cannon(CannonDesign design, UUID world, Vector cannonOffset, BlockFace ca * @return location of the cannon */ public Location getLocation() { - return design.getAllCannonBlocks(this).get(0); + return getFirstCannonBlock(); } /** @@ -151,8 +156,11 @@ public Location getRandomBarrelBlock() { List barrel = design.getBarrelBlocks(this); if (!barrel.isEmpty()) return barrel.get(random.nextInt(barrel.size())); - List all = design.getAllCannonBlocks(this); - return all.get(random.nextInt(all.size())); + + OffsetSchematic offsetSchematic = getOffsetSchematic(); + List positions = offsetSchematic.realBlocks().positions(); + IBlock position = positions.get(random.nextInt(positions.size())); + return new Location(getWorldBukkit(), position.x(), position.y(), position.z()); } @@ -737,39 +745,24 @@ public MessageEnum destroyCannon(boolean breakBlocks, boolean canExplode, BreakC * this will force the cannon to show up at this location - all blocks will be overwritten */ public void show() { - for (SimpleBlock cBlock : design.getAllCannonBlocks(this.getCannonDirection())) { - Block wBlock = cBlock.toLocation(getWorldBukkit(), getOffset()).getBlock(); - //todo check show - wBlock.setBlockData(cBlock.getBlockData()); - //wBlock.setBlockData(cBlock); - } + OffsetSchematic offsetSchematic = getOffsetSchematic(); + + SchematicWorldProcessorImpl.getProcessor().place( + offsetSchematic, + cannonPosition.getWorld() + ); } /** * this will force the cannon blocks to become AIR */ public void hide() { - //remove only attachable block - for (SimpleBlock cBlock : design.getAllCannonBlocks(this.getCannonDirection())) { - Block wBlock = cBlock.toLocation(getWorldBukkit(), getOffset()).getBlock(); - //if that block is not loaded - - if (wBlock.getState() instanceof Attachable) { - //Cannons.logger().info("hide " + wBlock.getType()); - wBlock.setType(Material.AIR); - //wBlock.setData((byte) 0, false); - } - } - - //remove all - for (SimpleBlock cBlock : design.getAllCannonBlocks(this.getCannonDirection())) { - Block wBlock = cBlock.toLocation(getWorldBukkit(), getOffset()).getBlock(); + OffsetSchematic offsetSchematic = getOffsetSchematic(); - if (wBlock.getType() != Material.AIR) { - wBlock.setType(Material.AIR); - // wBlock.setData((byte) 0, false); - } - } + SchematicWorldProcessorImpl.getProcessor().destroy( + offsetSchematic, + cannonPosition.getWorld() + ); } @@ -777,10 +770,24 @@ public void hide() { * breaks all cannon blocks of the cannon */ private void breakAllCannonBlocks() { - List locList = design.getAllCannonBlocks(this); - for (Location loc : locList) { - loc.getBlock().breakNaturally(); - } + OffsetSchematic offsetSchematic = getOffsetSchematic(); + + SchematicWorldProcessorImpl.getProcessor().breakNaturally( + offsetSchematic, + cannonPosition.getWorld() + ); + } + + public OffsetSchematic getOffsetSchematic() { + Schematic schematic = design.getSchematicMap().get(cannonPosition.getCannonDirection()); + Vector off = cannonPosition.getOffset(); + + return new OffsetSchematicImpl( + off.getBlockX(), + off.getBlockY(), + off.getBlockZ(), + schematic.positions() + ); } @@ -791,15 +798,20 @@ private void breakAllCannonBlocks() { * @return - true if it is part of this cannon */ public boolean isCannonBlock(Block block) { - if (!getWorld().equals(block.getWorld().getUID())) { + UUID world = cannonPosition.getWorld(); + if (!world.equals(block.getWorld().getUID())) { return false; } - for (SimpleBlock designBlock : design.getAllCannonBlocks(getCannonDirection())) { - if (designBlock.compareMaterialAndLoc(block, getOffset())) { + OffsetSchematic offsetSchematic = getOffsetSchematic(); + SchematicWorldProcessorImpl processor = SchematicWorldProcessorImpl.getProcessor(); + for (IBlock schemBlock : offsetSchematic.realBlocks()) { + IBlock obtain = processor.registry().getBlock(block.getX(), block.getY(), block.getZ(), world); + if (obtain.matches(schemBlock)) { return true; } } + return false; } @@ -976,8 +988,9 @@ public boolean isSentryAutomatic() { * @return - first block of the cannon */ public Location getFirstCannonBlock() { - return design.getAllCannonBlocks(getCannonDirection()).get(0).toLocation(getWorldBukkit(), getOffset()); - + OffsetSchematic offsetSchematic = getOffsetSchematic(); + IBlock first = offsetSchematic.realBlocks().positions().get(0); + return new Location(getWorldBukkit(), first.x(), first.y(), first.z()); } /** diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java index 8a8294e6..a62cd62a 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java @@ -583,7 +583,7 @@ public boolean isAllowedMaterial(Material m) { @Override public String toString() { - return "designID:" + designID + " name:" + designName + " blocks:" + getAllCannonBlocks(BlockFace.NORTH).size(); + return "designID:" + designID + " name:" + designName + " blocks:" + schematicMap.get(BlockFace.NORTH).positions().size(); } /** diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java index 6723ba4a..dda0bec6 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java @@ -1,10 +1,12 @@ package at.pavlov.cannons.schematic.block; +import lombok.Getter; import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; import org.bukkit.NamespacedKey; import org.bukkit.block.Block; +@Getter public class BlockImpl implements IBlock { private final Block block; diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java index 1df166c7..02932dc9 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java @@ -2,6 +2,7 @@ import at.pavlov.cannons.schematic.block.BlockImpl; +import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; import me.vaan.schematiclib.base.namespace.NamespaceHandler; import org.bukkit.Bukkit; @@ -47,4 +48,10 @@ public void breakNaturally(IBlock iBlock, UUID uuid) { iBlock.z() ).breakNaturally(); } + + // should be unused + @Override + public BlockKey toMaterial(BlockKey blockKey) { + return blockKey; + } } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java index 25edf4b6..9c035bc8 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java @@ -1,18 +1,24 @@ package at.pavlov.cannons.schematic.world; +import at.pavlov.cannons.schematic.block.BlockImpl; import at.pavlov.cannons.schematic.namespace.MinecraftNamespaceHandler; import lombok.Getter; +import me.vaan.schematiclib.base.block.IBlock; import me.vaan.schematiclib.base.namespace.NamespaceHandler; import me.vaan.schematiclib.base.namespace.NamespaceRegistry; import me.vaan.schematiclib.base.world.SchematicWorldProcessor; +import org.bukkit.block.Block; + +import java.util.UUID; public class SchematicWorldProcessorImpl implements SchematicWorldProcessor { @Getter private static final SchematicWorldProcessorImpl processor = new SchematicWorldProcessorImpl(); private final NamespaceRegistry registry; + private final MinecraftNamespaceHandler mcHandler = new MinecraftNamespaceHandler(); private SchematicWorldProcessorImpl() { - this.registry = new NamespaceRegistry("minecraft", new MinecraftNamespaceHandler()); + this.registry = new NamespaceRegistry("minecraft", mcHandler); } @Override @@ -29,5 +35,9 @@ public void registerReflectionNamespace(String namespace, String classToFind, Na registry.registerNamespaceHandler(namespace, handler); } + + public Block getRaw(IBlock block, UUID world) { + return ((BlockImpl) mcHandler.get(block.x(), block.y(), block.z(), world)).getBlock(); + } } From f1ca317029d5a69ddb0ef86a3f96bddaa53b18b5 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 23 Sep 2025 11:37:42 +0200 Subject: [PATCH 16/48] Nuke allCannonBlocks for schematic support, the systems are now separate --- .../pavlov/cannons/cannon/CannonBlocks.java | 94 +++---------------- .../pavlov/cannons/cannon/CannonDesign.java | 47 +--------- .../pavlov/cannons/cannon/CannonManager.java | 6 +- .../pavlov/cannons/cannon/DesignStorage.java | 67 ++++++------- .../cannons/utils/DesignComparator.java | 6 +- 5 files changed, 51 insertions(+), 169 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonBlocks.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonBlocks.java index fef85f12..1b8ff935 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonBlocks.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonBlocks.java @@ -1,6 +1,8 @@ package at.pavlov.cannons.cannon; import at.pavlov.cannons.container.SimpleBlock; +import lombok.Getter; +import lombok.Setter; import org.bukkit.util.Vector; import java.util.ArrayList; @@ -10,11 +12,12 @@ * it is not suggested to create new instances of it but instead * use it to get the positions of the various stuff */ +@Setter +@Getter public class CannonBlocks { private Vector rotationCenter; //center off all rotation blocks private Vector muzzle; //center off all muzzle blocks - spawing Vector for snowball - private ArrayList allCannonBlocks = new ArrayList<>(); private ArrayList barrelBlocks = new ArrayList<>(); private ArrayList chestsAndSigns = new ArrayList<>(); private ArrayList redstoneTorches = new ArrayList<>(); @@ -50,109 +53,36 @@ public Vector getFiringTrigger() { return redstoneTrigger.get(0); return null; } - - public Vector getRotationCenter() { - return rotationCenter; - } - public void setRotationCenter(Vector rotationCenter) { - this.rotationCenter = rotationCenter; - } - - public Vector getMuzzle() { - return muzzle; - } - public void setMuzzle(Vector muzzle) { - this.muzzle = muzzle; - } - - public ArrayList getAllCannonBlocks() { - return allCannonBlocks; - } - public void setAllCannonBlocks(ArrayList allCannonBlocks) { - this.allCannonBlocks = allCannonBlocks; - } - public void addAllCannonBlocks(SimpleBlock add) { - this.allCannonBlocks.add(add); - } - public ArrayList getBarrelBlocks() { - return barrelBlocks; - } - public void setBarrel(ArrayList barrelBlocks) { - this.barrelBlocks = barrelBlocks; - } - public void addBarrel(Vector add) { + public void addBarrelBlocks(Vector add) { this.barrelBlocks.add(add); } - public ArrayList getRedstoneTorches() { - return redstoneTorches; - } - public void setRedstoneTorches(ArrayList redstoneTorches) { - this.redstoneTorches = redstoneTorches; - } - public void addRedstoneTorch(Vector add) { + public void addRedstoneTorch(Vector add) { this.redstoneTorches.add(add); } - public ArrayList getRedstoneTrigger() { - return redstoneTrigger; - } - public void setRedstoneTrigger(ArrayList redstoneTrigger) { - this.redstoneTrigger = redstoneTrigger; - } - public void addRedstoneTrigger(Vector add) { + public void addRedstoneTrigger(Vector add) { this.redstoneTrigger.add(add); } - public ArrayList getRightClickTrigger() { - return rightClickTrigger; - } - public void setRightClickTrigger(ArrayList rightClickTrigger) { - this.rightClickTrigger = rightClickTrigger; - } - public void addRightClickTrigger(Vector add) { + public void addRightClickTrigger(Vector add) { this.rightClickTrigger.add(add); } - public ArrayList getChestsAndSigns() { - return chestsAndSigns; - } - public void setChestsAndSigns(ArrayList chestsAndSigns) { - this.chestsAndSigns = chestsAndSigns; - } - public void addChestsAndSigns(SimpleBlock add) { + public void addChestsAndSigns(SimpleBlock add) { this.chestsAndSigns.add(add); } - public ArrayList getRedstoneWiresAndRepeater() { - return redstoneWiresAndRepeater; - } - public void setRedstoneWiresAndRepeater(ArrayList redstoneWiresAndRepeater) { - this.redstoneWiresAndRepeater = redstoneWiresAndRepeater; - } - public void addRedstoneWiresAndRepeater(SimpleBlock add) { + public void addRedstoneWiresAndRepeater(SimpleBlock add) { this.redstoneWiresAndRepeater.add(add); } - public ArrayList getFiringIndicator() { - return firingIndicator; - } - public void setFiringIndicator(ArrayList firingIndicator) { - this.firingIndicator = firingIndicator; - } - public void addFiringIndicator(Vector add) { + public void addFiringIndicator(Vector add) { this.firingIndicator.add(add); } - public ArrayList getDestructibleBlocks() { - return destructibleBlocks; - } - public void setDestructibleBlocks(ArrayList destructibleBlocks) { - this.destructibleBlocks = destructibleBlocks; - } - public void addDestructibleBlocks(Vector add) { + public void addDestructibleBlocks(Vector add) { this.destructibleBlocks.add(add); } - } \ No newline at end of file diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java index a62cd62a..9d728918 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java @@ -6,6 +6,7 @@ import at.pavlov.cannons.container.SoundHolder; import at.pavlov.cannons.exchange.BExchanger; import at.pavlov.cannons.projectile.Projectile; +import at.pavlov.cannons.schematic.world.SchematicWorldProcessorImpl; import at.pavlov.internal.Key; import lombok.Data; import me.vaan.schematiclib.base.schematic.Schematic; @@ -249,43 +250,6 @@ public Location getFiringTrigger(Cannon cannon) } return null; } - - /** - * returns a list of all cannonBlocks - * @param cannonDirection - the direction the cannon is facing - * @return List of cannon blocks - */ - public List getAllCannonBlocks(BlockFace cannonDirection) - { - CannonBlocks cannonBlocks = cannonBlockMap.get(cannonDirection); - if (cannonBlocks != null) - { - return cannonBlocks.getAllCannonBlocks(); - } - - return new ArrayList<>(); - } - - - /** - * returns a list of all cannonBlocks - * @param cannon - * @return - */ - public List getAllCannonBlocks(Cannon cannon) - { - CannonBlocks cannonBlocks = cannonBlockMap.get(cannon.getCannonDirection()); - List locList = new ArrayList<>(); - if (cannonBlocks != null) - { - for (SimpleBlock block : cannonBlocks.getAllCannonBlocks()) - { - Vector vect = block.toVector(); - locList.add(vect.clone().add(cannon.getOffset()).toLocation(cannon.getWorldBukkit())); - } - } - return locList; - } /** * returns a list of all destructible blocks @@ -557,17 +521,14 @@ public void setRotatable(boolean isRotatable) public void putCannonBlockMap(BlockFace cannonDirection, CannonBlocks blocks) { - for (var block : blocks.getAllCannonBlocks()) { - allowedMaterials.add(block.getBlockData().getMaterial()); - } - cannonBlockMap.put(cannonDirection, blocks); } public void putSchematicMap(BlockFace cannonDirection, Schematic blocks) { - blocks.forEach(b -> { + Schematic parsed = SchematicWorldProcessorImpl.getProcessor().parseToMaterial(blocks); + parsed.forEach(b -> { Material m = Registry.MATERIAL.get( - new NamespacedKey(b.key().namespace(), b.key().key()) + NamespacedKey.minecraft(b.key().key()) ); allowedMaterials.add(m); diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java index d4c2d91e..c69c1b75 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java @@ -659,14 +659,14 @@ private Cannon checkCannon(Location cannonBlock, UUID owner) { // check of all directions for (BlockFace cannonDirection : blockFaces) { // for all blocks for the design - List designBlockList = cannonDesign.getAllCannonBlocks(cannonDirection); + Schematic schem = cannonDesign.getSchematicMap().get(cannonDirection); //check for empty entries - if (designBlockList.isEmpty()) { + if (schem.positions().isEmpty()) { plugin.logSevere("There are empty cannon design schematics in your design folder. Please check it."); return null; } - Schematic schem = cannonDesign.getSchematicMap().get(cannonDirection); + for (IBlock designBlock : schem) { // compare blocks if (!designBlock.key().equals(blockStuff.key())) { diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java index 7ed3b128..16e2d99f 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java @@ -3,6 +3,7 @@ import at.pavlov.cannons.Cannons; import at.pavlov.cannons.config.Config; import at.pavlov.cannons.schematic.formats.WorldEditFormat; +import at.pavlov.cannons.schematic.world.SchematicWorldProcessorImpl; import at.pavlov.internal.container.DesignFileName; import at.pavlov.cannons.container.ItemHolder; import at.pavlov.cannons.container.SimpleBlock; @@ -14,11 +15,6 @@ import at.pavlov.cannons.utils.ParseUtils; import at.pavlov.internal.Exchanger; import at.pavlov.internal.Key; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; -import com.sk89q.worldedit.util.io.Closer; import lombok.Getter; import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; @@ -31,30 +27,31 @@ import me.vaan.schematiclib.file.schematic.FileSchematic; import org.bukkit.Material; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.util.Vector; -import java.io.BufferedInputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Comparator; +import java.util.EnumSet; import java.util.List; +import java.util.Set; -public class DesignStorage -{ +public class DesignStorage { @Getter private static DesignStorage instance = null; - private final List cannonDesignList; + @Getter + private final List cannonDesignList; private final Cannons plugin; - private final List cannonBlockMaterials; + @Getter + private final Set cannonBlockMaterials; public static void initialize(Cannons cannons) { if (instance != null) @@ -67,7 +64,7 @@ public static void initialize(Cannons cannons) { private DesignStorage(Cannons cannons) { plugin = cannons; cannonDesignList = new ArrayList<>(); - cannonBlockMaterials = new ArrayList<>(); + cannonBlockMaterials = EnumSet.noneOf(Material.class); } /** @@ -121,13 +118,16 @@ public void loadCannonDesigns() Comparator comparator = new DesignComparator(); cannonDesignList.sort(comparator); - for (CannonDesign cannonDesign : getCannonDesignList()) { - for (SimpleBlock sBlock : cannonDesign.getAllCannonBlocks(BlockFace.NORTH)){ - Material material = sBlock.getBlockData().getMaterial(); - if (material != Material.AIR && !cannonBlockMaterials.contains(material)) { - cannonBlockMaterials.add(sBlock.getBlockData().getMaterial()); - } - } + SchematicWorldProcessorImpl processor = SchematicWorldProcessorImpl.getProcessor(); + for (CannonDesign cannonDesign : cannonDesignList) { + Schematic schematic = cannonDesign.getSchematicMap().get(BlockFace.NORTH); + Schematic materials = processor.parseToMaterial(schematic); + materials.positions().stream() + .map(IBlock::key) + .map(key -> NamespacedKey.minecraft(key.key())) + .map(Registry.MATERIAL::get) + .filter(mat -> mat != Material.AIR) + .forEach(cannonBlockMaterials::add); } @@ -474,7 +474,7 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF setMaximum(x, y, z, maxMuzzle); } //muzzle blocks need to be air - else the projectile would spawn in a block - cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, Material.AIR)); + //cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, Material.AIR)); filteredSchematic.add(new FileBlock(x, y, z, BlockKey.mc("air"))); } // ############# find the min and max for rotation blocks @@ -507,7 +507,7 @@ else if (!key.equals(bk(blockRedstoneTrigger))) { cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, key)); //Material.WALL_SIGN // firing blocks are also part of the cannon are // part of the cannon - cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRightClickTrigger)); + //cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRightClickTrigger)); filteredSchematic.add(new FileBlock(x, y, z, bk(replaceRightClickTrigger))); // this can be a destructible block if (!isInList(keysBlocksProtected, key)) @@ -522,8 +522,8 @@ else if (key.equals(bk(blockChestAndSign))) { // the previous blocks else { // all remaining blocks are loading interface or cannonBlocks - cannonBlocks.addBarrel(new Vector(x, y, z)); - cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, key)); + cannonBlocks.addBarrelBlocks(new Vector(x, y, z)); + //cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, key)); filteredSchematic.add(new FileBlock(x, y, z, key)); // this can be a destructible block if (!isInList(keysBlocksProtected, key)) @@ -534,7 +534,7 @@ else if (key.equals(bk(blockChestAndSign))) { else { cannonBlocks.addRedstoneTrigger(new Vector(x, y, z)); // buttons or levers are part of the cannon - cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRedstoneTrigger)); + //cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRedstoneTrigger)); filteredSchematic.add(new FileBlock(x, y, z, bk(replaceRedstoneTrigger))); // this can be a destructible block if (!isInList(keysBlocksProtected, key)) @@ -571,8 +571,6 @@ else if (key.equals(bk(blockChestAndSign))) { ) ); - for (SimpleBlock block : cannonBlocks.getAllCannonBlocks()) - block.directSubtract(compensation); for (Vector block : cannonBlocks.getBarrelBlocks()) block.subtract(compensation); for (SimpleBlock block : cannonBlocks.getChestsAndSigns()) @@ -693,13 +691,8 @@ public static String getPath() // Directory path here return "plugins/Cannons/designs/"; } - - public List getCannonDesignList() - { - return cannonDesignList; - } - - /** + + /** * returns the cannon design of the cannon * @param cannon the cannon * @return design of cannon @@ -738,11 +731,7 @@ public boolean hasDesign(String name){ return false; } - public List getCannonBlockMaterials() { - return cannonBlockMaterials; - } - - public boolean isCannonBlockMaterial(Material material) { + public boolean isCannonBlockMaterial(Material material) { return material != Material.AIR && cannonBlockMaterials.contains(material); } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/DesignComparator.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/DesignComparator.java index 28aaeab3..04223f3f 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/DesignComparator.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/DesignComparator.java @@ -2,6 +2,7 @@ import at.pavlov.cannons.Cannons; import at.pavlov.cannons.cannon.CannonDesign; +import me.vaan.schematiclib.base.schematic.Schematic; import org.bukkit.block.BlockFace; import java.util.Comparator; @@ -23,13 +24,14 @@ private Integer getCannonBlockAmount(CannonDesign design) { if (design == null) return 0; //if the design is invalid something goes wrong, message the user - if (design.getAllCannonBlocks(BlockFace.NORTH) == null) + Schematic schematic = design.getSchematicMap().get(BlockFace.NORTH); + if (schematic == null) { Cannons.logger().log(Level.SEVERE, "invalid cannon design for " + design.getDesignName()); return 0; } - return design.getAllCannonBlocks(BlockFace.NORTH).size(); + return schematic.positions().size(); } } From 5441a788d298b613735e4c8dfd1bd04b54c91d5d Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 23 Sep 2025 14:30:53 +0200 Subject: [PATCH 17/48] Add slimefun support --- .../namespace/SlimefunNamespaceHandler.java | 142 ++++++++++++++++++ .../world/SchematicWorldProcessorImpl.java | 13 +- cannons-bukkit/src/main/resources/plugin.yml | 7 +- 3 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java new file mode 100644 index 00000000..ae9141a8 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java @@ -0,0 +1,142 @@ +package at.pavlov.cannons.schematic.namespace; + +import at.pavlov.cannons.Cannons; +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; +import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import me.mrCookieSlime.Slimefun.api.BlockStorage; +import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; +import me.vaan.schematiclib.base.block.BlockKey; +import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.namespace.NamespaceHandler; +import me.vaan.schematiclib.file.block.FileBlock; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.HumanEntity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +// doesn't support handlers as we have no acting player +public class SlimefunNamespaceHandler implements NamespaceHandler { + @Override + public void place(IBlock iBlock, UUID uuid) { + World world = Bukkit.getWorld(uuid); + String id = iBlock.key().key(); + Location location = new Location(world, iBlock.x(), iBlock.y(), iBlock.z()); + Block block = location.getBlock(); + + SlimefunItem sfItem = SlimefunItem.getById(id.toUpperCase()); + if (sfItem == null) { + return; + } + + Material material = sfItem.getItem().getType(); + if (!material.isBlock()) { + return; + } + + if (Slimefun.getTickerTask().isDeletedSoon(location)) { + new BukkitRunnable() { + + @Override + public void run() { + if (Slimefun.getTickerTask().isDeletedSoon(location)) { + return; + } + + place(iBlock, uuid); + cancel(); + } + }.runTaskTimer(Cannons.getPlugin(), 1L, 4L); + return; + } + + block.setType(material); + if (Slimefun.getBlockDataService().isTileEntity(block.getType())) { + Slimefun.getBlockDataService().setBlockData(block, sfItem.getId()); + } + + BlockStorage.addBlockInfo(block, "id", sfItem.getId(), true); + } + + @Override + public IBlock get(int x, int y, int z, UUID uuid) { + World world = Bukkit.getWorld(uuid); + SlimefunItem item = BlockStorage.check(new Location(world, x, y, z)); + if (item == null) { + return null; + } + + String id = item.getId().toLowerCase(); + return new FileBlock(x, y, z, new BlockKey("slimefun", id)); + } + + @Override + public void destroy(IBlock iBlock, UUID uuid) { + World world = Bukkit.getWorld(uuid); + Location location = new Location(world, iBlock.x(), iBlock.y(), iBlock.z()); + + SlimefunItem sfItem = BlockStorage.check(location); + if (sfItem == null) { + return; // probably old data from a removed addon? + } + + BlockMenu inventory = BlockStorage.getInventory(location); + if (inventory != null) { + for (HumanEntity human : new ArrayList<>(inventory.toInventory().getViewers())) { + human.closeInventory(); + } + } + + BlockStorage.clearBlockInfo(location); + location.getBlock().setType(Material.AIR); + } + + @Override + public void breakNaturally(IBlock iBlock, UUID uuid) { + World world = Bukkit.getWorld(uuid); + Location location = new Location(world, iBlock.x(), iBlock.y(), iBlock.z()); + + SlimefunItem sfItem = BlockStorage.check(location); + if (sfItem == null) { + return; // probably old data from a removed addon? + } + + List drops = new ArrayList<>(sfItem.getDrops()); + BlockMenu inventory = BlockStorage.getInventory(location); + if (inventory != null) { + for (HumanEntity human : new ArrayList<>(inventory.toInventory().getViewers())) { + human.closeInventory(); + } + } + + BlockStorage.clearBlockInfo(location); + + for (ItemStack drop : drops) { + if (drop != null && drop.getType() != Material.AIR) { + world.dropItemNaturally(location, drop); + } + } + + location.getBlock().setType(Material.AIR); + } + + @Override + public BlockKey toMaterial(BlockKey blockKey) { + SlimefunItem sfItem = SlimefunItem.getById(blockKey.key().toUpperCase()); + if (sfItem == null) { + return BlockKey.mc("air"); + } + + String materialType = sfItem.getItem().getType().getKey().getKey(); + return BlockKey.mc(materialType); + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java index 9c035bc8..5078ff0d 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java @@ -2,6 +2,7 @@ import at.pavlov.cannons.schematic.block.BlockImpl; import at.pavlov.cannons.schematic.namespace.MinecraftNamespaceHandler; +import at.pavlov.cannons.schematic.namespace.SlimefunNamespaceHandler; import lombok.Getter; import me.vaan.schematiclib.base.block.IBlock; import me.vaan.schematiclib.base.namespace.NamespaceHandler; @@ -13,7 +14,7 @@ public class SchematicWorldProcessorImpl implements SchematicWorldProcessor { @Getter - private static final SchematicWorldProcessorImpl processor = new SchematicWorldProcessorImpl(); + private static final SchematicWorldProcessorImpl processor = new SchematicWorldProcessorImpl().registerAll(); private final NamespaceRegistry registry; private final MinecraftNamespaceHandler mcHandler = new MinecraftNamespaceHandler(); @@ -39,5 +40,15 @@ public void registerReflectionNamespace(String namespace, String classToFind, Na public Block getRaw(IBlock block, UUID world) { return ((BlockImpl) mcHandler.get(block.x(), block.y(), block.z(), world)).getBlock(); } + + private SchematicWorldProcessorImpl registerAll() { + registerReflectionNamespace( + "slimefun", + "io.github.thebusybiscuit.slimefun4.implementation.Slimefun", + new SlimefunNamespaceHandler() + ); + + return this; + } } diff --git a/cannons-bukkit/src/main/resources/plugin.yml b/cannons-bukkit/src/main/resources/plugin.yml index 14c3a02e..55c7cf1d 100644 --- a/cannons-bukkit/src/main/resources/plugin.yml +++ b/cannons-bukkit/src/main/resources/plugin.yml @@ -3,7 +3,12 @@ main: at.pavlov.cannons.Cannons api-version: 1.13 version: ${version} depend: [WorldEdit] -softdepend: [Vault, Movecraft, Movecraft-Combat, PlaceholderAPI] +softdepend: + - Vault + - Movecraft + - Movecraft-Combat + - PlaceholderAPI + - Slimefun authors: [DerPavlov, Vaan1310] description: Fire block build cannons and smash your enemies folia-supported: true From a004ba9c122e0143199068528fc52b2359129482 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 23 Sep 2025 14:38:48 +0200 Subject: [PATCH 18/48] Add syntax helper for save too --- .../src/main/java/at/pavlov/cannons/commands/Commands.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java index 213db7ab..705a52a5 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java @@ -329,6 +329,7 @@ public static void help(Player player) { } @Subcommand("save") + @Syntax(" ") public static void save(Player player, int xA, int yA, int zA, int xB, int yB, int zB, String name) { String fullName = name + ".vschem"; Schematic schematic = SchematicWorldProcessorImpl.getProcessor().schematicOf(xA, yA, zA, xB, yB, zB, player.getWorld().getUID()); From b6b566060761948a314a81bd4fa71ba6bcd565a0 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 23 Sep 2025 16:27:57 +0200 Subject: [PATCH 19/48] No need to load twice --- cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java index 3d33b713..c7ee73b7 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/Cannons.java @@ -180,7 +180,7 @@ public void onEnable() { ProjectileManager.initialize(this); CannonSelector.initialize(this); - DesignStorage.getInstance().loadCannonDesigns(); + //DesignStorage.getInstance().loadCannonDesigns(); ProjectileStorage.getInstance().loadProjectiles(); CannonManager.getInstance().updateCannons(); UserMessages.getInstance().loadLanguage(); From d4bf73502244d1ab3994fd2834304f79a3fe210f Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 23 Sep 2025 16:28:13 +0200 Subject: [PATCH 20/48] Add consistency check --- .../at/pavlov/cannons/cannon/DesignStorage.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java index 16e2d99f..4d1f9be2 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java @@ -395,6 +395,15 @@ private static BlockKey bk(BlockData data) { return new BlockKey(key.getNamespace(), key.getKey()); } + private static boolean isSchematicValid(Schematic schematic) { + try { + SchematicWorldProcessorImpl.getProcessor().parseToMaterial(schematic); + return true; + } catch (Throwable throwable) { + return false; + } + } + /** * loads the schematic of the config file * @param cannonDesign design of the cannon @@ -428,6 +437,10 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF //plugin.logDebug("design: " + schematicFile); Schematic blocks = getSchematic(schemFile, bk(blockIgnore)); + if (!isSchematicValid(blocks)) { + plugin.logSevere("Schematic " + schematicFile + " is invalid, maybe it has custom blocks whose plugin has been removed?"); + return false; + } if (blocks == null) return false; ICoord max = blocks.getMax(); From 1bb1cad6d8f934b67d7ccac688fdd3cee1c5c690 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 23 Sep 2025 16:28:53 +0200 Subject: [PATCH 21/48] Add utility stuff and use them --- .../pavlov/cannons/schematic/RetryUntil.java | 29 +++++++++++++++++++ .../namespace/SlimefunNamespaceHandler.java | 25 +++++----------- .../pavlov/cannons/utils/SchemLibUtils.java | 13 +++++++++ 3 files changed, 49 insertions(+), 18 deletions(-) create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/RetryUntil.java create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/utils/SchemLibUtils.java diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/RetryUntil.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/RetryUntil.java new file mode 100644 index 00000000..d0a19afb --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/RetryUntil.java @@ -0,0 +1,29 @@ +package at.pavlov.cannons.schematic; + +import at.pavlov.cannons.Cannons; +import lombok.AllArgsConstructor; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.function.Supplier; + +@AllArgsConstructor +public class RetryUntil extends BukkitRunnable { + private final Supplier booleanSupplier; + private final Runnable runnable; + + public RetryUntil(Supplier booleanSupplier) { + this(booleanSupplier, () -> {}); + } + + @Override + public void run() { + if (booleanSupplier.get()) return; + + runnable.run(); + cancel(); + } + + public void start() { + runTaskTimer(Cannons.getPlugin(), 1L, 4L); + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java index ae9141a8..e155bb24 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java @@ -1,8 +1,8 @@ package at.pavlov.cannons.schematic.namespace; -import at.pavlov.cannons.Cannons; +import at.pavlov.cannons.schematic.RetryUntil; +import at.pavlov.cannons.utils.SchemLibUtils; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; -import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; @@ -17,11 +17,9 @@ import org.bukkit.block.Block; import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.UUID; // doesn't support handlers as we have no acting player @@ -44,18 +42,10 @@ public void place(IBlock iBlock, UUID uuid) { } if (Slimefun.getTickerTask().isDeletedSoon(location)) { - new BukkitRunnable() { - - @Override - public void run() { - if (Slimefun.getTickerTask().isDeletedSoon(location)) { - return; - } - - place(iBlock, uuid); - cancel(); - } - }.runTaskTimer(Cannons.getPlugin(), 1L, 4L); + new RetryUntil( + () -> Slimefun.getTickerTask().isDeletedSoon(location), + () -> place(iBlock, uuid) + ).start(); return; } @@ -136,7 +126,6 @@ public BlockKey toMaterial(BlockKey blockKey) { return BlockKey.mc("air"); } - String materialType = sfItem.getItem().getType().getKey().getKey(); - return BlockKey.mc(materialType); + return SchemLibUtils.materialKey(sfItem.getItem().getType()); } } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/SchemLibUtils.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/SchemLibUtils.java new file mode 100644 index 00000000..a081b15a --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/SchemLibUtils.java @@ -0,0 +1,13 @@ +package at.pavlov.cannons.utils; + +import me.vaan.schematiclib.base.block.BlockKey; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.jetbrains.annotations.NotNull; + +public class SchemLibUtils { + public static BlockKey materialKey(@NotNull Material mat) { + NamespacedKey key = mat.getKey(); + return BlockKey.mc(key.getKey()); + } +} From 4ec937f126543ee5d16443195880dc8c50fad962 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 23 Sep 2025 16:29:02 +0200 Subject: [PATCH 22/48] Add ItemsAdder support --- cannons-bukkit/pom.xml | 14 +++- .../namespace/ItemsAdderNamespaceHandler.java | 75 +++++++++++++++++++ .../world/SchematicWorldProcessorImpl.java | 7 ++ cannons-bukkit/src/main/resources/plugin.yml | 1 + 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/ItemsAdderNamespaceHandler.java diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 34c48077..72e93962 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -65,6 +65,10 @@ true + + matteodev + https://maven.devs.beer/ + @@ -125,7 +129,15 @@ com.github.Intybyte SchematicLib - 7e2dbdc1bf + 1faa409806 + + + + + dev.lone + api-itemsadder + 4.0.10 + provided diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/ItemsAdderNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/ItemsAdderNamespaceHandler.java new file mode 100644 index 00000000..7fa0f724 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/ItemsAdderNamespaceHandler.java @@ -0,0 +1,75 @@ +package at.pavlov.cannons.schematic.namespace; + +import at.pavlov.cannons.schematic.RetryUntil; +import at.pavlov.cannons.utils.SchemLibUtils; +import dev.lone.itemsadder.api.CustomBlock; +import me.vaan.schematiclib.base.block.BlockKey; +import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.namespace.NamespaceHandler; +import me.vaan.schematiclib.file.block.FileBlock; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; + +import java.util.UUID; + +public class ItemsAdderNamespaceHandler implements NamespaceHandler { + + @Override + public void place(IBlock iBlock, UUID uuid) { + World world = Bukkit.getWorld(uuid); + Location location = new Location(world, iBlock.x(), iBlock.y(), iBlock.z()); + + String realKey = iBlock.key().key().replace('$', ':'); + CustomBlock.place(realKey, location); + } + + @Override + public IBlock get(int x, int y, int z, UUID uuid) { + World world = Bukkit.getWorld(uuid); + Location location = new Location(world, x, y, z); + + Block bBlock = location.getBlock(); + CustomBlock iaBlock = CustomBlock.byAlreadyPlaced(bBlock); + if (iaBlock == null) { + return null; + } + + // war crimes go brrrrrrrrrr + String replaced = iaBlock.getNamespacedID().replace(':', '$'); + return new FileBlock(x, y, z, new BlockKey("itemsadder", replaced)); + } + + @Override + public void destroy(IBlock iBlock, UUID uuid) { + World world = Bukkit.getWorld(uuid); + Location location = new Location(world, iBlock.x(), iBlock.y(), iBlock.z()); + + if (!CustomBlock.remove(location)) { + new RetryUntil( + () -> !CustomBlock.remove(location) + ).start(); + } + } + + @Override + public void breakNaturally(IBlock iBlock, UUID uuid) { + World world = Bukkit.getWorld(uuid); + Location location = new Location(world, iBlock.x(), iBlock.y(), iBlock.z()); + + Block bBlock = location.getBlock(); + CustomBlock iaBlock = CustomBlock.byAlreadyPlaced(bBlock); + iaBlock.drop(location); + + destroy(iBlock, uuid); + } + + @Override + public BlockKey toMaterial(BlockKey blockKey) { + String realKey = blockKey.key().replace('$', ':'); + Material material = CustomBlock.getBaseBlockData(realKey).getMaterial(); + return SchemLibUtils.materialKey(material); + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java index 5078ff0d..9195eac9 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java @@ -1,6 +1,7 @@ package at.pavlov.cannons.schematic.world; import at.pavlov.cannons.schematic.block.BlockImpl; +import at.pavlov.cannons.schematic.namespace.ItemsAdderNamespaceHandler; import at.pavlov.cannons.schematic.namespace.MinecraftNamespaceHandler; import at.pavlov.cannons.schematic.namespace.SlimefunNamespaceHandler; import lombok.Getter; @@ -48,6 +49,12 @@ private SchematicWorldProcessorImpl registerAll() { new SlimefunNamespaceHandler() ); + registerReflectionNamespace( + "itemsadder", + "dev.lone.itemsadder.api.CustomBlock", + new ItemsAdderNamespaceHandler() + ); + return this; } } diff --git a/cannons-bukkit/src/main/resources/plugin.yml b/cannons-bukkit/src/main/resources/plugin.yml index 55c7cf1d..e8801dd5 100644 --- a/cannons-bukkit/src/main/resources/plugin.yml +++ b/cannons-bukkit/src/main/resources/plugin.yml @@ -9,6 +9,7 @@ softdepend: - Movecraft-Combat - PlaceholderAPI - Slimefun + - ItemsAdder authors: [DerPavlov, Vaan1310] description: Fire block build cannons and smash your enemies folia-supported: true From 8eaeb7cf3bf53945dc719dddff7dc3851af85d89 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Wed, 24 Sep 2025 12:08:42 +0200 Subject: [PATCH 23/48] Read BlockKeys instead of blockdata --- .../pavlov/cannons/cannon/CannonDesign.java | 25 ++-- .../pavlov/cannons/cannon/DesignStorage.java | 121 ++++++++---------- .../at/pavlov/cannons/utils/ParseUtils.java | 15 +++ 3 files changed, 78 insertions(+), 83 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java index 9d728918..9f155ce1 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonDesign.java @@ -9,6 +9,7 @@ import at.pavlov.cannons.schematic.world.SchematicWorldProcessorImpl; import at.pavlov.internal.Key; import lombok.Data; +import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.schematic.Schematic; import org.bukkit.Location; import org.bukkit.Material; @@ -181,18 +182,18 @@ //constructionblocks: - private BlockData schematicBlockTypeIgnore; //this block this is ignored in the schematic file - private BlockData schematicBlockTypeMuzzle; //location of the muzzle - private BlockData schematicBlockTypeRotationCenter; //location of the roatation - private BlockData schematicBlockTypeChestAndSign; //locations of the chest and sign - private BlockData schematicBlockTypeRedstoneTorch; //locations of the redstone torches - private BlockData schematicBlockTypeRedstoneWireAndRepeater; //locations of the redstone wires and repeaters - private BlockData schematicBlockTypeRedstoneTrigger; //locations of button or levers - private BlockData ingameBlockTypeRedstoneTrigger; //block which is placed instead of the place holder - private BlockData schematicBlockTypeRightClickTrigger; //locations of the right click trigger - private BlockData ingameBlockTypeRightClickTrigger; //block type of the tigger in game - private BlockData schematicBlockTypeFiringIndicator; //location of the firing indicator - private List schematicBlockTypeProtected; //list of blocks that are protected from explosions (e.g. buttons) + private BlockKey schematicBlockTypeIgnore; //this block this is ignored in the schematic file + private BlockKey schematicBlockTypeMuzzle; //location of the muzzle + private BlockKey schematicBlockTypeRotationCenter; //location of the roatation + private BlockKey schematicBlockTypeChestAndSign; //locations of the chest and sign + private BlockKey schematicBlockTypeRedstoneTorch; //locations of the redstone torches + private BlockKey schematicBlockTypeRedstoneWireAndRepeater; //locations of the redstone wires and repeaters + private BlockKey schematicBlockTypeRedstoneTrigger; //locations of button or levers + private BlockKey ingameBlockTypeRedstoneTrigger; //block which is placed instead of the place holder + private BlockKey schematicBlockTypeRightClickTrigger; //locations of the right click trigger + private BlockKey ingameBlockTypeRightClickTrigger; //block type of the tigger in game + private BlockKey schematicBlockTypeFiringIndicator; //location of the firing indicator + private List schematicBlockTypeProtected; //list of blocks that are protected from explosions (e.g. buttons) //cannon design block lists for every direction (NORTH, EAST, SOUTH, WEST) private final HashMap cannonBlockMap = new HashMap<>(); diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java index 4d1f9be2..7800b608 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/DesignStorage.java @@ -2,19 +2,19 @@ import at.pavlov.cannons.Cannons; import at.pavlov.cannons.config.Config; -import at.pavlov.cannons.schematic.formats.WorldEditFormat; -import at.pavlov.cannons.schematic.world.SchematicWorldProcessorImpl; -import at.pavlov.internal.container.DesignFileName; import at.pavlov.cannons.container.ItemHolder; import at.pavlov.cannons.container.SimpleBlock; import at.pavlov.cannons.container.SoundHolder; import at.pavlov.cannons.exchange.BExchanger; import at.pavlov.cannons.exchange.ExchangeLoader; +import at.pavlov.cannons.schematic.formats.WorldEditFormat; +import at.pavlov.cannons.schematic.world.SchematicWorldProcessorImpl; import at.pavlov.cannons.utils.CannonsUtil; import at.pavlov.cannons.utils.DesignComparator; import at.pavlov.cannons.utils.ParseUtils; import at.pavlov.internal.Exchanger; import at.pavlov.internal.Key; +import at.pavlov.internal.container.DesignFileName; import lombok.Getter; import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; @@ -29,7 +29,6 @@ import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.BlockFace; -import org.bukkit.block.data.BlockData; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.util.Vector; @@ -88,7 +87,7 @@ public void loadCannonDesigns() //clear designList before loading cannonDesignList.clear(); - + // check if design folder is empty or does not exist if (CannonsUtil.isFolderEmpty(getPath())) { @@ -112,9 +111,9 @@ public void loadCannonDesigns() if (loadDesignSchematic(cannonDesign, designFile.schematicString())) cannonDesignList.add(cannonDesign); } - + //sort the list so the designs with more cannon blocks comes first - //important if there is a design with one block less but else identically + //important if there is a design with one block less but else identically Comparator comparator = new DesignComparator(); cannonDesignList.sort(comparator); @@ -140,7 +139,7 @@ public void loadCannonDesigns() /** * returns a list with valid cannon designs (.yml + .schematic) - * + * * @return */ private ArrayList getDesignFiles() { @@ -373,28 +372,23 @@ private void loadDesignYml(CannonDesign cannonDesign, String ymlFile) cannonDesign.setSoundSelected(new SoundHolder(cannonDesignConfig.getString("sounds.selected","BLOCK_ANVIL_LAND:1:2"))); // constructionBlocks - cannonDesign.setSchematicBlockTypeIgnore(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.ignore", "minecraft:sand"))); - cannonDesign.setSchematicBlockTypeMuzzle(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.muzzle", "minecraft:snow_block"))); - cannonDesign.setSchematicBlockTypeFiringIndicator(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.firingIndicator", "minecraft:torch"))); - cannonDesign.setSchematicBlockTypeRotationCenter(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.rotationCenter", "minecraft:redstone_ore"))); - cannonDesign.setSchematicBlockTypeChestAndSign(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.chestAndSign", "minecraft:oak_wall_sign"))); - cannonDesign.setSchematicBlockTypeRedstoneTorch(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.redstoneTorch", "minecraft:redstone_torch"))); - cannonDesign.setSchematicBlockTypeRedstoneWireAndRepeater(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.restoneWireAndRepeater", "minecraft:repeater"))); + cannonDesign.setSchematicBlockTypeIgnore(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.ignore", "minecraft:sand"))); + cannonDesign.setSchematicBlockTypeMuzzle(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.muzzle", "minecraft:snow_block"))); + cannonDesign.setSchematicBlockTypeFiringIndicator(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.firingIndicator", "minecraft:torch"))); + cannonDesign.setSchematicBlockTypeRotationCenter(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.rotationCenter", "minecraft:redstone_ore"))); + cannonDesign.setSchematicBlockTypeChestAndSign(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.chestAndSign", "minecraft:oak_wall_sign"))); + cannonDesign.setSchematicBlockTypeRedstoneTorch(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.redstoneTorch", "minecraft:redstone_torch"))); + cannonDesign.setSchematicBlockTypeRedstoneWireAndRepeater(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.restoneWireAndRepeater", "minecraft:repeater"))); // RedstoneTrigger - cannonDesign.setSchematicBlockTypeRedstoneTrigger(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.redstoneTrigger.schematic", "minecraft:lever"))); - cannonDesign.setIngameBlockTypeRedstoneTrigger(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.redstoneTrigger.ingame", "minecraft:stone_button"))); + cannonDesign.setSchematicBlockTypeRedstoneTrigger(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.redstoneTrigger.schematic", "minecraft:lever"))); + cannonDesign.setIngameBlockTypeRedstoneTrigger(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.redstoneTrigger.ingame", "minecraft:stone_button"))); // rightClickTrigger - cannonDesign.setSchematicBlockTypeRightClickTrigger(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.rightClickTrigger.schematic", "minecraft:torch"))); - cannonDesign.setIngameBlockTypeRightClickTrigger(CannonsUtil.createBlockData(cannonDesignConfig.getString("constructionBlocks.rightClickTrigger.ingame", "minecraft:torch"))); + cannonDesign.setSchematicBlockTypeRightClickTrigger(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.rightClickTrigger.schematic", "minecraft:torch"))); + cannonDesign.setIngameBlockTypeRightClickTrigger(ParseUtils.toBlockKey(cannonDesignConfig.getString("constructionBlocks.rightClickTrigger.ingame", "minecraft:torch"))); // protected Blocks - cannonDesign.setSchematicBlockTypeProtected(ParseUtils.toBlockDataList(cannonDesignConfig.getStringList("constructionBlocks.protectedBlocks"))); + cannonDesign.setSchematicBlockTypeProtected(ParseUtils.toBlockKeyList(cannonDesignConfig.getStringList("constructionBlocks.protectedBlocks"))); } - private static BlockKey bk(BlockData data) { - NamespacedKey key = data.getMaterial().getKey(); - return new BlockKey(key.getNamespace(), key.getKey()); - } - private static boolean isSchematicValid(Schematic schematic) { try { SchematicWorldProcessorImpl.getProcessor().parseToMaterial(schematic); @@ -418,25 +412,24 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF // convert all schematic blocks from the config to BaseBlocks so they // can be rotated - BlockData blockIgnore = cannonDesign.getSchematicBlockTypeIgnore(); - BlockData blockMuzzle = cannonDesign.getSchematicBlockTypeMuzzle(); - BlockData blockFiringIndicator = cannonDesign.getSchematicBlockTypeFiringIndicator(); - BlockData blockRotationCenter = cannonDesign.getSchematicBlockTypeRotationCenter(); - BlockData blockChestAndSign = cannonDesign.getSchematicBlockTypeChestAndSign(); - BlockData blockRedstoneTorch = cannonDesign.getSchematicBlockTypeRedstoneTorch(); - BlockData blockRedstoneWireAndRepeater = cannonDesign.getSchematicBlockTypeRedstoneWireAndRepeater(); - BlockData blockRedstoneTrigger = cannonDesign.getSchematicBlockTypeRedstoneTrigger(); - BlockData blockRightClickTrigger = cannonDesign.getSchematicBlockTypeRightClickTrigger(); - BlockData replaceRedstoneTrigger = cannonDesign.getIngameBlockTypeRedstoneTrigger(); - BlockData replaceRightClickTrigger = cannonDesign.getIngameBlockTypeRightClickTrigger(); - List blockProtectedList = new ArrayList<>(cannonDesign.getSchematicBlockTypeProtected()); - List keysBlocksProtected = blockProtectedList.stream().map(DesignStorage::bk).toList(); + BlockKey blockIgnore = cannonDesign.getSchematicBlockTypeIgnore(); + BlockKey blockMuzzle = cannonDesign.getSchematicBlockTypeMuzzle(); + BlockKey blockFiringIndicator = cannonDesign.getSchematicBlockTypeFiringIndicator(); + BlockKey blockRotationCenter = cannonDesign.getSchematicBlockTypeRotationCenter(); + BlockKey blockChestAndSign = cannonDesign.getSchematicBlockTypeChestAndSign(); + BlockKey blockRedstoneTorch = cannonDesign.getSchematicBlockTypeRedstoneTorch(); + BlockKey blockRedstoneWireAndRepeater = cannonDesign.getSchematicBlockTypeRedstoneWireAndRepeater(); + BlockKey blockRedstoneTrigger = cannonDesign.getSchematicBlockTypeRedstoneTrigger(); + BlockKey blockRightClickTrigger = cannonDesign.getSchematicBlockTypeRightClickTrigger(); + BlockKey replaceRedstoneTrigger = cannonDesign.getIngameBlockTypeRedstoneTrigger(); + BlockKey replaceRightClickTrigger = cannonDesign.getIngameBlockTypeRightClickTrigger(); + List blockProtectedList = new ArrayList<>(cannonDesign.getSchematicBlockTypeProtected()); // get facing of the cannon BlockFace cannonDirection = cannonDesign.getDefaultHorizontalFacing(); //plugin.logDebug("design: " + schematicFile); - Schematic blocks = getSchematic(schemFile, bk(blockIgnore)); + Schematic blocks = getSchematic(schemFile, blockIgnore); if (!isSchematicValid(blocks)) { plugin.logSevere("Schematic " + schematicFile + " is invalid, maybe it has custom blocks whose plugin has been removed?"); return false; @@ -476,7 +469,7 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF // ############# find the min and max for muzzle blocks so the // cannonball is fired from the middle BlockKey key = sblock.key(); - if (key.equals(bk(blockMuzzle))) { + if (key.equals(blockMuzzle)) { // reset for the first entry if (firstEntryMuzzle) { firstEntryMuzzle = false; @@ -491,7 +484,7 @@ private boolean loadDesignSchematic(CannonDesign cannonDesign, String schematicF filteredSchematic.add(new FileBlock(x, y, z, BlockKey.mc("air"))); } // ############# find the min and max for rotation blocks - else if (key.equals(bk(blockRotationCenter))) { + else if (key.equals(blockRotationCenter)) { // reset for the first entry if (firstEntryRotation) { firstEntryRotation = false; @@ -503,31 +496,31 @@ else if (key.equals(bk(blockRotationCenter))) { } } // ############# redstoneTorch - else if (key.equals(bk(blockRedstoneTorch))) { + else if (key.equals(blockRedstoneTorch)) { cannonBlocks.addRedstoneTorch(new Vector(x, y, z)); } // ############# redstoneWire and Repeater - else if (key.equals(bk(blockRedstoneWireAndRepeater))) { + else if (key.equals(blockRedstoneWireAndRepeater)) { cannonBlocks.addRedstoneWiresAndRepeater(new SimpleBlock(x, y, z, Material.REPEATER)); } // ############# redstoneTrigger - else if (!key.equals(bk(blockRedstoneTrigger))) { - if (key.equals(bk(blockRightClickTrigger))) { + else if (!key.equals(blockRedstoneTrigger)) { + if (key.equals(blockRightClickTrigger)) { cannonBlocks.addRightClickTrigger(new Vector(x, y, z)); //can be also a sign - if (key.equals(bk(blockChestAndSign))) + if (key.equals(blockChestAndSign)) // the id does not matter, but the data is important for signs cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, key)); //Material.WALL_SIGN // firing blocks are also part of the cannon are // part of the cannon //cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRightClickTrigger)); - filteredSchematic.add(new FileBlock(x, y, z, bk(replaceRightClickTrigger))); + filteredSchematic.add(new FileBlock(x, y, z, replaceRightClickTrigger)); // this can be a destructible block - if (!isInList(keysBlocksProtected, key)) + if (!isInList(blockProtectedList, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } // ############# chests and signs - else if (key.equals(bk(blockChestAndSign))) { + else if (key.equals(blockChestAndSign)) { // the id does not matter, but the data is important for signs cannonBlocks.addChestsAndSigns(new SimpleBlock(x, y, z, key)); //Material.WALL_SIGN } @@ -539,7 +532,7 @@ else if (key.equals(bk(blockChestAndSign))) { //cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, key)); filteredSchematic.add(new FileBlock(x, y, z, key)); // this can be a destructible block - if (!isInList(keysBlocksProtected, key)) + if (!isInList(blockProtectedList, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } } @@ -548,16 +541,16 @@ else if (key.equals(bk(blockChestAndSign))) { cannonBlocks.addRedstoneTrigger(new Vector(x, y, z)); // buttons or levers are part of the cannon //cannonBlocks.addAllCannonBlocks(new SimpleBlock(x, y, z, replaceRedstoneTrigger)); - filteredSchematic.add(new FileBlock(x, y, z, bk(replaceRedstoneTrigger))); + filteredSchematic.add(new FileBlock(x, y, z, replaceRedstoneTrigger)); // this can be a destructible block - if (!isInList(keysBlocksProtected, key)) + if (!isInList(blockProtectedList, key)) cannonBlocks.addDestructibleBlocks(new Vector(x, y, z)); } // ############# firingIndicator // can be everywhere on the cannon - if (key.equals(bk(blockFiringIndicator))) + if (key.equals(blockFiringIndicator)) cannonBlocks.addFiringIndicator(new Vector(x, y, z)); } @@ -607,20 +600,6 @@ else if (key.equals(bk(blockChestAndSign))) { cannonDesign.putCannonBlockMap(cannonDirection, cannonBlocks); cannonDesign.putSchematicMap(cannonDirection, new FileSchematic(actualSchematic)); - //rotate blocks for the next iteration - blockIgnore = CannonsUtil.roateBlockFacingClockwise(blockIgnore); - blockMuzzle = CannonsUtil.roateBlockFacingClockwise(blockMuzzle); - blockFiringIndicator = CannonsUtil.roateBlockFacingClockwise(blockFiringIndicator); - blockRotationCenter = CannonsUtil.roateBlockFacingClockwise(blockRotationCenter); - blockChestAndSign = CannonsUtil.roateBlockFacingClockwise(blockChestAndSign); - blockRedstoneTorch = CannonsUtil.roateBlockFacingClockwise(blockRedstoneTorch); - blockRedstoneTrigger = CannonsUtil.roateBlockFacingClockwise(blockRedstoneTrigger); - blockRightClickTrigger = CannonsUtil.roateBlockFacingClockwise(blockRightClickTrigger); - replaceRedstoneTrigger = CannonsUtil.roateBlockFacingClockwise(replaceRedstoneTrigger); - replaceRightClickTrigger = CannonsUtil.roateBlockFacingClockwise(replaceRightClickTrigger); - - blockProtectedList = blockProtectedList.stream().map(CannonsUtil::roateBlockFacingClockwise).toList(); - //rotate schematic blocks ArrayList newList = new ArrayList<>(); for (IBlock simpleBlock : blocks){ @@ -686,11 +665,11 @@ private void copyFile(String fileName) CannonsUtil.copyFile(plugin.getResource("designs/" + fileName + ".schematic"), SchematicFile); } } - + private boolean isInList(List list, T block) { if (block == null) return true; - + for (T listBlock : list) { if (listBlock != null && listBlock.equals(block)) @@ -698,7 +677,7 @@ private boolean isInList(List list, T block) } return false; } - + public static String getPath() { // Directory path here @@ -714,7 +693,7 @@ public CannonDesign getDesign(Cannon cannon) { return getDesign(cannon.getDesignID()); } - + /** * returns the cannon design by its id * @param designId Name of the design diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/ParseUtils.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/ParseUtils.java index 425e78a1..18e12c04 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/ParseUtils.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/ParseUtils.java @@ -4,6 +4,7 @@ import at.pavlov.cannons.container.ItemHolder; import at.pavlov.cannons.container.SpawnEntityHolder; import at.pavlov.internal.container.SpawnMaterialHolder; +import me.vaan.schematiclib.base.block.BlockKey; import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.Material; @@ -139,6 +140,20 @@ public static List toBlockDataList(List stringList) { return blockDataList; } + public static BlockKey toBlockKey(String entry) { + return BlockKey.fromString(entry.split("\\[")[0]); + } + + public static List toBlockKeyList(List stringList) { + List blockKeyList = new ArrayList<>(); + + for (String str : stringList) { + blockKeyList.add(toBlockKey(str)); + } + + return blockKeyList; + } + /** * returns a list of ItemHolder * @param stringList list of Materials as strings From 185d90bb0598a348fa36dda5a5aabc8fad3eda46 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Wed, 24 Sep 2025 12:10:09 +0200 Subject: [PATCH 24/48] Optimizations and logDebug schematic process time --- .../pavlov/cannons/cannon/CannonManager.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java index c69c1b75..03616cbf 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java @@ -26,6 +26,7 @@ import me.vaan.schematiclib.base.schematic.Schematic; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Block; @@ -35,6 +36,7 @@ import org.jetbrains.annotations.NotNull; import java.text.DecimalFormat; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; @@ -525,6 +527,7 @@ public Cannon getCannon(Location cannonBlock, UUID owner, boolean silent) { //check if there is a cannon at this location Cannon cannon = checkCannon(cannonBlock, owner); + plugin.logDebug("Time to process Schematic: " + (System.nanoTime() - startTime) + "ns"); //if there is no cannon, exit if (cannon == null) @@ -642,24 +645,31 @@ public static Cannon getCannon(UUID uid) { private Cannon checkCannon(Location cannonBlock, UUID owner) { // is this block material used for a cannon design Block block = cannonBlock.getBlock(); - IBlock blockStuff = SchematicWorldProcessorImpl - .getProcessor() - .registry() + SchematicWorldProcessorImpl processor = SchematicWorldProcessorImpl.getProcessor(); + IBlock blockStuff = processor.registry() .getBlock(block.getX(), block.getY(), block.getZ(), block.getWorld().getUID()); + Material material = block.getType(); if (!isValidCannonBlock(block)) return null; World world = cannonBlock.getWorld(); - var designList = DesignStorage.getInstance().getCannonDesignList(); - designList = designList.stream().filter(it -> it.isAllowedMaterial(block.getType())).toList(); + + var allDesigns = DesignStorage.getInstance().getCannonDesignList(); + List designList = new ArrayList<>(); + for (CannonDesign it : allDesigns) { + if (it.isAllowedMaterial(material)) { + designList.add(it); + } + } // check all cannon design if this block is part of the design for (CannonDesign cannonDesign : designList) { + var schemMap = cannonDesign.getSchematicMap(); // check of all directions for (BlockFace cannonDirection : blockFaces) { // for all blocks for the design - Schematic schem = cannonDesign.getSchematicMap().get(cannonDirection); + Schematic schem = schemMap.get(cannonDirection); //check for empty entries if (schem.positions().isEmpty()) { plugin.logSevere("There are empty cannon design schematics in your design folder. Please check it."); @@ -687,7 +697,7 @@ private Cannon checkCannon(Location cannonBlock, UUID owner) { schem.positions() ); - boolean matches = SchematicWorldProcessorImpl.getProcessor().matches(offsetSchematic, world.getUID()); + boolean matches = processor.matches(offsetSchematic, world.getUID()); if (matches) { return new Cannon( cannonDesign, @@ -700,6 +710,7 @@ private Cannon checkCannon(Location cannonBlock, UUID owner) { } } } + return null; } From 8ac6684ac25286856b5d517205d4eda5a87ad0aa Mon Sep 17 00:00:00 2001 From: Intybyte Date: Wed, 24 Sep 2025 14:50:49 +0200 Subject: [PATCH 25/48] Add chat output --- .../src/main/java/at/pavlov/cannons/commands/Commands.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java index 705a52a5..5bafa566 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java @@ -341,8 +341,10 @@ public static void save(Player player, int xA, int yA, int zA, int xB, int yB, i try { format.save(file, schematic); } catch (Throwable e) { - throw new RuntimeException(e); + sendMessage(player, ChatColor.RED + "[Cannons] Failed to save"); } + + sendMessage(player, ChatColor.GREEN + "[Cannons] Successful save"); } } From 42cf0ab66c973d6d7dbbe9582dde030931800650 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Wed, 24 Sep 2025 17:20:25 +0200 Subject: [PATCH 26/48] Optimizations --- cannons-bukkit/pom.xml | 2 +- .../at/pavlov/cannons/listener/BlockListener.java | 1 + .../at/pavlov/cannons/listener/EntityListener.java | 1 + .../java/at/pavlov/cannons/utils/EventUtils.java | 14 +++++++++++--- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 72e93962..c87e996c 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -129,7 +129,7 @@ com.github.Intybyte SchematicLib - 1faa409806 + 60a6751b57 diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/BlockListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/BlockListener.java index 8a47a94f..e1ea3e3d 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/BlockListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/BlockListener.java @@ -58,6 +58,7 @@ public void blockExplodeEvent(BlockExplodeEvent event) { } //search for destroyed cannons + event.blockList().removeIf(it -> it.getType().isAir()); EventUtils.handleExplosion(event.blockList()); } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/EntityListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/EntityListener.java index f5bad471..06df3625 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/EntityListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/EntityListener.java @@ -47,6 +47,7 @@ public void EntityExplode(EntityExplodeEvent event) { return; } + event.blockList().removeIf(it -> it.getType().isAir()); EventUtils.handleExplosion(event.blockList()); } } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java index a1ae674d..0a428341 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java @@ -3,8 +3,10 @@ import at.pavlov.cannons.Enum.BreakCause; import at.pavlov.cannons.cannon.Cannon; import at.pavlov.cannons.cannon.CannonManager; +import org.bukkit.Location; import org.bukkit.block.Block; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.UUID; @@ -19,17 +21,23 @@ private EventUtils() {} public static void handleExplosion(List blocklist) { CannonManager cannonManager = CannonManager.getInstance(); HashSet remove = new HashSet<>(); + HashMap cannonHashMap = new HashMap<>(); // first search if a barrel block was destroyed. for (Block block : blocklist) { - Cannon cannon = cannonManager.getCannon(block.getLocation(), null); + if (block == null) continue; + Location location = block.getLocation(); + if (block.getType().isAir()) continue; + + Cannon cannon = cannonManager.getCannon(location, null); // if it is a cannon block if (cannon == null) { continue; } - if (cannon.isDestructibleBlock(block.getLocation())) { + cannonHashMap.put(block, cannon); + if (cannon.isDestructibleBlock(location)) { //this cannon is destroyed remove.add(cannon.getUID()); } @@ -38,7 +46,7 @@ public static void handleExplosion(List blocklist) { //iterate again and remove all block of intact cannons for (int i = 0; i < blocklist.size(); i++) { Block block = blocklist.get(i); - Cannon cannon = cannonManager.getCannon(block.getLocation(), null); + Cannon cannon = cannonHashMap.get(block); // if it is a cannon block and the cannon is not destroyed (see above) if (cannon == null || remove.contains(cannon.getUID())) { From 5becf1a3f251eea781e44fb95687a8544d62cb80 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Wed, 24 Sep 2025 23:15:32 +0200 Subject: [PATCH 27/48] Update and use new optimization --- cannons-bukkit/pom.xml | 2 +- .../java/at/pavlov/cannons/cannon/Cannon.java | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index c87e996c..aba7bfef 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -129,7 +129,7 @@ com.github.Intybyte SchematicLib - 60a6751b57 + 4abe119bf1 diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java index 2e1299d2..c3d34528 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java @@ -90,11 +90,21 @@ public class Cannon implements ICannon, Rotational { //TODO make a vector util class and add this there private final static Vector noVelocity = new Vector(0,0,0); + @Getter + private final OffsetSchematic offsetSchematic; public Cannon(CannonDesign design, UUID world, Vector cannonOffset, BlockFace cannonDirection, UUID owner) { this.design = design; this.cannonPosition = new CannonPosition(cannonDirection, cannonOffset, world, false, noVelocity.clone()); + + Schematic schematic = design.getSchematicMap().get(cannonPosition.getCannonDirection()); + this.offsetSchematic = new ConstantOffsetSchematic( + cannonOffset.getBlockX(), + cannonOffset.getBlockY(), + cannonOffset.getBlockZ(), + schematic.positions() + ); boolean noFee = design.getEconomyBuildingCost() instanceof EmptyExchanger; this.mainData = new CannonMainData( UUID.randomUUID(),null, noFee, owner, true); @@ -157,7 +167,6 @@ public Location getRandomBarrelBlock() { if (!barrel.isEmpty()) return barrel.get(random.nextInt(barrel.size())); - OffsetSchematic offsetSchematic = getOffsetSchematic(); List positions = offsetSchematic.realBlocks().positions(); IBlock position = positions.get(random.nextInt(positions.size())); return new Location(getWorldBukkit(), position.x(), position.y(), position.z()); @@ -745,8 +754,6 @@ public MessageEnum destroyCannon(boolean breakBlocks, boolean canExplode, BreakC * this will force the cannon to show up at this location - all blocks will be overwritten */ public void show() { - OffsetSchematic offsetSchematic = getOffsetSchematic(); - SchematicWorldProcessorImpl.getProcessor().place( offsetSchematic, cannonPosition.getWorld() @@ -757,8 +764,6 @@ public void show() { * this will force the cannon blocks to become AIR */ public void hide() { - OffsetSchematic offsetSchematic = getOffsetSchematic(); - SchematicWorldProcessorImpl.getProcessor().destroy( offsetSchematic, cannonPosition.getWorld() @@ -770,8 +775,6 @@ public void hide() { * breaks all cannon blocks of the cannon */ private void breakAllCannonBlocks() { - OffsetSchematic offsetSchematic = getOffsetSchematic(); - SchematicWorldProcessorImpl.getProcessor().breakNaturally( offsetSchematic, cannonPosition.getWorld() @@ -803,7 +806,6 @@ public boolean isCannonBlock(Block block) { return false; } - OffsetSchematic offsetSchematic = getOffsetSchematic(); SchematicWorldProcessorImpl processor = SchematicWorldProcessorImpl.getProcessor(); for (IBlock schemBlock : offsetSchematic.realBlocks()) { IBlock obtain = processor.registry().getBlock(block.getX(), block.getY(), block.getZ(), world); @@ -988,7 +990,6 @@ public boolean isSentryAutomatic() { * @return - first block of the cannon */ public Location getFirstCannonBlock() { - OffsetSchematic offsetSchematic = getOffsetSchematic(); IBlock first = offsetSchematic.realBlocks().positions().get(0); return new Location(getWorldBukkit(), first.x(), first.y(), first.z()); } From 24f31f25a523a6a72e2771c026fdcd2bc8f53107 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 25 Sep 2025 09:45:06 +0200 Subject: [PATCH 28/48] Optimize explosion handling and BlockImpl --- .../java/at/pavlov/cannons/cannon/Cannon.java | 23 ++++++------------- .../cannons/schematic/block/BlockImpl.java | 6 +++-- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java index c3d34528..3586e14d 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java @@ -34,6 +34,7 @@ import lombok.Getter; import lombok.Setter; import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.schematic.ConstantOffsetSchematic; import me.vaan.schematiclib.base.schematic.OffsetSchematic; import me.vaan.schematiclib.base.schematic.OffsetSchematicImpl; import me.vaan.schematiclib.base.schematic.Schematic; @@ -50,7 +51,6 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import org.bukkit.material.Attachable; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; @@ -90,21 +90,12 @@ public class Cannon implements ICannon, Rotational { //TODO make a vector util class and add this there private final static Vector noVelocity = new Vector(0,0,0); - @Getter - private final OffsetSchematic offsetSchematic; - public Cannon(CannonDesign design, UUID world, Vector cannonOffset, BlockFace cannonDirection, UUID owner) { this.design = design; this.cannonPosition = new CannonPosition(cannonDirection, cannonOffset, world, false, noVelocity.clone()); Schematic schematic = design.getSchematicMap().get(cannonPosition.getCannonDirection()); - this.offsetSchematic = new ConstantOffsetSchematic( - cannonOffset.getBlockX(), - cannonOffset.getBlockY(), - cannonOffset.getBlockZ(), - schematic.positions() - ); boolean noFee = design.getEconomyBuildingCost() instanceof EmptyExchanger; this.mainData = new CannonMainData( UUID.randomUUID(),null, noFee, owner, true); @@ -167,7 +158,7 @@ public Location getRandomBarrelBlock() { if (!barrel.isEmpty()) return barrel.get(random.nextInt(barrel.size())); - List positions = offsetSchematic.realBlocks().positions(); + List positions = getOffsetSchematic().realBlocks().positions(); IBlock position = positions.get(random.nextInt(positions.size())); return new Location(getWorldBukkit(), position.x(), position.y(), position.z()); } @@ -755,7 +746,7 @@ public MessageEnum destroyCannon(boolean breakBlocks, boolean canExplode, BreakC */ public void show() { SchematicWorldProcessorImpl.getProcessor().place( - offsetSchematic, + getOffsetSchematic(), cannonPosition.getWorld() ); } @@ -765,7 +756,7 @@ public void show() { */ public void hide() { SchematicWorldProcessorImpl.getProcessor().destroy( - offsetSchematic, + getOffsetSchematic(), cannonPosition.getWorld() ); } @@ -776,7 +767,7 @@ public void hide() { */ private void breakAllCannonBlocks() { SchematicWorldProcessorImpl.getProcessor().breakNaturally( - offsetSchematic, + getOffsetSchematic(), cannonPosition.getWorld() ); } @@ -807,7 +798,7 @@ public boolean isCannonBlock(Block block) { } SchematicWorldProcessorImpl processor = SchematicWorldProcessorImpl.getProcessor(); - for (IBlock schemBlock : offsetSchematic.realBlocks()) { + for (IBlock schemBlock : getOffsetSchematic().realBlocks()) { IBlock obtain = processor.registry().getBlock(block.getX(), block.getY(), block.getZ(), world); if (obtain.matches(schemBlock)) { return true; @@ -990,7 +981,7 @@ public boolean isSentryAutomatic() { * @return - first block of the cannon */ public Location getFirstCannonBlock() { - IBlock first = offsetSchematic.realBlocks().positions().get(0); + IBlock first = getOffsetSchematic().realBlocks().positions().get(0); return new Location(getWorldBukkit(), first.x(), first.y(), first.z()); } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java index dda0bec6..4e7a159b 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/block/BlockImpl.java @@ -9,9 +9,12 @@ @Getter public class BlockImpl implements IBlock { private final Block block; + private final BlockKey key; public BlockImpl(Block block) { this.block = block; + NamespacedKey key = block.getType().getKey(); + this.key = BlockKey.mc(key.getKey()); } @Override @@ -31,7 +34,6 @@ public int z() { @Override public BlockKey key() { - NamespacedKey key = block.getType().getKey(); - return BlockKey.mc(key.getKey()); + return this.key; } } \ No newline at end of file From d51c8218235356b06f947c10f1a19bbeff30195c Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 25 Sep 2025 09:45:16 +0200 Subject: [PATCH 29/48] Optimize explosion handling --- .../src/main/java/at/pavlov/cannons/utils/EventUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java index 0a428341..38414571 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java @@ -30,7 +30,7 @@ public static void handleExplosion(List blocklist) { Location location = block.getLocation(); if (block.getType().isAir()) continue; - Cannon cannon = cannonManager.getCannon(location, null); + Cannon cannon = cannonManager.getCannonFromStorage(location); // if it is a cannon block if (cannon == null) { continue; From 244593f5bd562ffe2975a0e1907d191dfaf24a13 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 25 Sep 2025 09:45:49 +0200 Subject: [PATCH 30/48] Update SchematicLib version --- cannons-bukkit/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index aba7bfef..001bc784 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -129,7 +129,7 @@ com.github.Intybyte SchematicLib - 4abe119bf1 + d0f209a1f1 From 532755b35ddfeae30541f3602b5d336cb13bea2c Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 25 Sep 2025 16:04:39 +0200 Subject: [PATCH 31/48] Add wand for easier schematic creation --- .../at/pavlov/cannons/commands/Commands.java | 24 ++++++++++--- .../cannons/listener/PlayerListener.java | 17 ++++++++++ .../pavlov/cannons/schematic/SchemUtil.java | 34 +++++++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/SchemUtil.java diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java index 5bafa566..e871d0f4 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java @@ -18,6 +18,7 @@ import at.pavlov.cannons.projectile.Projectile; import at.pavlov.cannons.projectile.ProjectileStorage; import at.pavlov.cannons.projectile.definitions.ProjectileDefinitionLoader; +import at.pavlov.cannons.schematic.SchemUtil; import at.pavlov.cannons.schematic.world.SchematicWorldProcessorImpl; import at.pavlov.cannons.utils.CannonSelector; import at.pavlov.cannons.utils.CannonsUtil; @@ -322,17 +323,32 @@ public static void onObserver(Player player, String[] args) { @Subcommand("schematic") @CommandPermission("cannons.admin.reload") public class onSchematic extends BaseCommand { + private static final SchematicWorldProcessorImpl processor = SchematicWorldProcessorImpl.getProcessor(); @Default public static void help(Player player) { - sendMessage(player, ChatColor.RED + "Usage '/cannons schematic save '"); + sendMessage(player, ChatColor.RED + "Usage '/cannons schematic '"); + } + + @Subcommand("tool") + public static void tool(Player player) { + player.getInventory().addItem(SchemUtil.SELECT_TOOL.clone()); } @Subcommand("save") - @Syntax(" ") - public static void save(Player player, int xA, int yA, int zA, int xB, int yB, int zB, String name) { + @Syntax("") + public static void save(Player player, String name) { String fullName = name + ".vschem"; - Schematic schematic = SchematicWorldProcessorImpl.getProcessor().schematicOf(xA, yA, zA, xB, yB, zB, player.getWorld().getUID()); + if (!SchemUtil.coord1.getWorld().equals(SchemUtil.coord2.getWorld())) { + sendMessage(player, ChatColor.RED + "[Cannons] Coordinates must be in the same world"); + return; + } + + Schematic schematic = processor.schematicOf( + SchemUtil.coord1.getX(), SchemUtil.coord1.getY(), SchemUtil.coord1.getZ(), + SchemUtil.coord2.getX(), SchemUtil.coord2.getY(), SchemUtil.coord2.getZ(), + SchemUtil.coord1.getWorld().getUID() + ); String fullPath = DesignStorage.getPath() + fullName; File file = new File(fullPath); diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/PlayerListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/PlayerListener.java index 03a1b3b3..1f16482d 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/PlayerListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/PlayerListener.java @@ -15,10 +15,12 @@ import at.pavlov.cannons.projectile.Projectile; import at.pavlov.cannons.projectile.ProjectileManager; import at.pavlov.cannons.projectile.ProjectileStorage; +import at.pavlov.cannons.schematic.SchemUtil; import at.pavlov.cannons.utils.CannonSelector; import at.pavlov.cannons.utils.CannonsUtil; import at.pavlov.cannons.utils.SoundUtils; import com.cryptomorin.xseries.XPotion; +import org.bukkit.ChatColor; import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.Sound; @@ -229,6 +231,21 @@ public void playerInteract(PlayerInteractEvent event) { return; } + // handle schematic positioning + ItemStack mainHand = player.getInventory().getItemInMainHand(); + if (mainHand.isSimilar(SchemUtil.SELECT_TOOL)) { + if (action == Action.RIGHT_CLICK_BLOCK) { + SchemUtil.coord1 = clickedBlock; + player.sendMessage(ChatColor.GREEN + "[Cannons] Saved position 1"); + } else if (action == Action.LEFT_CLICK_BLOCK) { + SchemUtil.coord2 = clickedBlock; + player.sendMessage(ChatColor.GREEN + "[Cannons] Saved position 2"); + } + + event.setCancelled(true); + return; + } + final Location barrel = clickedBlock.getLocation(); //try if the player has really nothing in his hands, or minecraft is blocking it diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/SchemUtil.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/SchemUtil.java new file mode 100644 index 00000000..50e7c201 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/SchemUtil.java @@ -0,0 +1,34 @@ +package at.pavlov.cannons.schematic; + +import at.pavlov.cannons.Cannons; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; + +public class SchemUtil { + public static Block coord1 = null; + public static Block coord2 = null; + + public static final NamespacedKey CANNON_KEY = new NamespacedKey(Cannons.getPlugin(), "selector"); + public static final ItemStack SELECT_TOOL = getSelectTool(); + private static ItemStack getSelectTool() { + ItemStack item = new ItemStack(Material.BLAZE_ROD); + ItemMeta meta = item.getItemMeta(); + if (meta == null) { + meta = Bukkit.getItemFactory().getItemMeta(Material.BLAZE_ROD); + } + + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + meta.addEnchant(Enchantment.UNBREAKING, 1, true); + meta.getPersistentDataContainer().set(CANNON_KEY, PersistentDataType.BOOLEAN, true); + + item.setItemMeta(meta); + return item; + } +} From ebc0b963ca2e2fd38ac4503b1712626b002bb3c5 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 25 Sep 2025 18:06:51 +0200 Subject: [PATCH 32/48] Custom name for new wand --- .../src/main/java/at/pavlov/cannons/schematic/SchemUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/SchemUtil.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/SchemUtil.java index 50e7c201..8db3bdfa 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/SchemUtil.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/SchemUtil.java @@ -2,6 +2,7 @@ import at.pavlov.cannons.Cannons; import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.block.Block; @@ -24,6 +25,7 @@ private static ItemStack getSelectTool() { meta = Bukkit.getItemFactory().getItemMeta(Material.BLAZE_ROD); } + meta.setDisplayName(ChatColor.RESET + "Cannon Select Tool"); meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); meta.addEnchant(Enchantment.UNBREAKING, 1, true); meta.getPersistentDataContainer().set(CANNON_KEY, PersistentDataType.BOOLEAN, true); From 9073867b9c89ee9084d88f6e1280925a7f72e765 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 25 Sep 2025 18:07:20 +0200 Subject: [PATCH 33/48] Add command completions --- .../commands/CannonsCommandManager.java | 19 +++++++++++++++---- .../at/pavlov/cannons/commands/Commands.java | 3 ++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/CannonsCommandManager.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/CannonsCommandManager.java index a0c61fa7..90e14a40 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/CannonsCommandManager.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/CannonsCommandManager.java @@ -1,12 +1,16 @@ package at.pavlov.cannons.commands; import at.pavlov.cannons.Enum.SelectCannon; +import at.pavlov.cannons.cannon.DesignStorage; +import at.pavlov.cannons.projectile.ProjectileStorage; import co.aikar.commands.CommandIssuer; import co.aikar.commands.InvalidCommandArgument; import co.aikar.commands.PaperCommandManager; +import com.google.common.collect.ImmutableList; import org.bukkit.command.CommandSender; import org.bukkit.plugin.Plugin; +import java.util.Collections; import java.util.Locale; import java.util.Set; import java.util.regex.Pattern; @@ -14,12 +18,13 @@ public class CannonsCommandManager extends PaperCommandManager { public CannonsCommandManager(Plugin plugin) { super(plugin); - this.registerContexts(); + this.registerCommandContexts(); + this.registerCommandCompletions(); } - private void registerContexts() { - var context = this.getCommandContexts(); - context.registerContext(SelectCannon.class, c -> { + private void registerCommandContexts() { + var commandContexts = this.getCommandContexts(); + commandContexts.registerContext(SelectCannon.class, c -> { String select = c.popFirstArg(); switch (select.toLowerCase(Locale.ROOT)) { case "mob" -> { @@ -43,6 +48,12 @@ private void registerContexts() { }); } + private void registerCommandCompletions() { + var commandCompletions = this.getCommandCompletions(); + commandCompletions.registerCompletion("cannon_designs", c -> Collections.unmodifiableList(DesignStorage.getInstance().getDesignIds())); + commandCompletions.registerCompletion("cannon_projectiles" , c -> Collections.unmodifiableList(ProjectileStorage.getProjectileIds())); + } + private static final Pattern COMMA = Pattern.compile(","); private static final Pattern PIPE = Pattern.compile("\\|"); diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java index e871d0f4..45640363 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/commands/Commands.java @@ -43,7 +43,6 @@ import java.util.concurrent.CompletableFuture; @CommandAlias("cannons") -@SuppressWarnings("deprecation") public class Commands extends BaseCommand { private static final String tag = "[Cannons] "; @@ -170,6 +169,7 @@ public static void onList(CommandSender sender, @Optional String arg) { @Subcommand("create") @Syntax("[DESIGN]") @CommandPermission("cannons.admin.create") + @CommandCompletion("@cannon_designs") public static void onCreate(Player player, String arg) { //check if the design name is valid if (!designStorage.hasDesign(arg)) { @@ -188,6 +188,7 @@ public static void onCreate(Player player, String arg) { @Subcommand("give") @Syntax("[PROJECTILE] ") @CommandPermission("cannons.admin.give") + @CommandCompletion("@cannon_projectiles") public static void onGive(Player player, String projectileString, @Default("1") int amount) { //check if the projectile id is valid Projectile projectile = ProjectileStorage.getProjectile(projectileString); From 872f84a34cd04d01d0125b0fa873920c536cf46e Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 25 Sep 2025 18:10:15 +0200 Subject: [PATCH 34/48] Update FEATURES.md --- FEATURES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/FEATURES.md b/FEATURES.md index e1f2bc4c..31cd3387 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -6,6 +6,9 @@ New features - New area commands - Mohist compatibility (kind of, you need to use particle aiming) - Folia support +- Custom projectile definitions (Custom gravity, drag, water drag, constant acceleration, Custom model data and more) +- Custom blocks support (Slimefun & ItemsAdder so far, requires custom format) +- Command completions Fixes: --------------- @@ -41,6 +44,9 @@ FireTask API: Exchange API: - You can define your own exchanges for cannons creation requirement, example at [CannonsEXP](https://github.com/Intybyte/CannonsEXP) +Schematic Processing API: +- You can define your own custom blocks to add by defining a namespace and adding it to SchematicWorldProcessorImpl + Projectiles: - Projectile type events now give the FlyingProjectile - ProjectilePiercingEvent is now cancellable From 9786d16f0997598323585d704e044826af8de24b Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 25 Sep 2025 18:18:27 +0200 Subject: [PATCH 35/48] Fix double select with tool --- .../java/at/pavlov/cannons/listener/PlayerListener.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/PlayerListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/PlayerListener.java index 1f16482d..5a7479b2 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/PlayerListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/PlayerListener.java @@ -231,6 +231,10 @@ public void playerInteract(PlayerInteractEvent event) { return; } + if (event.getHand() != EquipmentSlot.HAND) { + return; + } + // handle schematic positioning ItemStack mainHand = player.getInventory().getItemInMainHand(); if (mainHand.isSimilar(SchemUtil.SELECT_TOOL)) { @@ -257,10 +261,6 @@ public void playerInteract(PlayerInteractEvent event) { // ############ select a cannon #################### if (isCannonSelect(event, clickedBlock, cannon)) return; - if (event.getHand() != EquipmentSlot.HAND) { - return; - } - boolean isRMB = action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK; if ((isRMB || event.getAction() == Action.PHYSICAL) && cannon != null) { // prevent eggs and snowball from firing when loaded into the gun From bfbc7690cf0b94584a88e1d2528238991aada5cd Mon Sep 17 00:00:00 2001 From: Intybyte Date: Sun, 28 Sep 2025 17:08:11 +0200 Subject: [PATCH 36/48] Move dependency --- api-internal/pom.xml | 12 ++++++++++++ cannons-bukkit/pom.xml | 5 ----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/api-internal/pom.xml b/api-internal/pom.xml index f4df5edd..39cfaa02 100644 --- a/api-internal/pom.xml +++ b/api-internal/pom.xml @@ -15,12 +15,24 @@ UTF-8 + + + jitpack.io + https://jitpack.io + + + com.google.code.gson gson 2.11.0 + + com.github.Intybyte + SchematicLib + 6b6ddd9a83 + org.jetbrains annotations diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 001bc784..440a200c 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -126,11 +126,6 @@ 1.0.7 compile - - com.github.Intybyte - SchematicLib - d0f209a1f1 - From 4de083e8075bfc29505394d6d73173b822ff8803 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 29 Sep 2025 13:52:13 +0200 Subject: [PATCH 37/48] Optimize getLocation/getFirstCannonBlock --- .../src/main/java/at/pavlov/cannons/cannon/Cannon.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java index 3586e14d..9d0e7a06 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java @@ -981,8 +981,14 @@ public boolean isSentryAutomatic() { * @return - first block of the cannon */ public Location getFirstCannonBlock() { - IBlock first = getOffsetSchematic().realBlocks().positions().get(0); - return new Location(getWorldBukkit(), first.x(), first.y(), first.z()); + Vector vec = cannonPosition.getOffset(); + OffsetSchematic schematic = getOffsetSchematic(); + IBlock first = schematic.positions().get(0); + return new Location(getWorldBukkit(), + first.x() + vec.getBlockX(), + first.y() + vec.getBlockY(), + first.z() + vec.getBlockZ() + ); } /** From bd6ead82a024137f34c71d57a2c639bb48abb5e9 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 30 Sep 2025 21:01:59 +0200 Subject: [PATCH 38/48] Fix creating cannon on the fly on crafts --- .../pavlov/cannons/cannon/CannonManager.java | 7 +-- .../hooks/movecraft/MovecraftHook.java | 3 +- .../listener/TeleportPlayerHandler.java | 44 +++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TeleportPlayerHandler.java diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java index 03616cbf..fa40ea7e 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java @@ -590,15 +590,16 @@ private boolean fireCannonBeforeCreateEvent(Cannon cannon, MessageEnum message, return event; }); + MessageEnum msg = cbceEvent.getMessage(); //add cannon to the list if everything was fine and return the cannon - if (!cbceEvent.isCancelled() && cbceEvent.getMessage() != null && cbceEvent.getMessage() == MessageEnum.CannonCreated) { + if (!cbceEvent.isCancelled() && msg == MessageEnum.CannonCreated) { return true; } //send messages - if (!silent) { + if (!silent && msg != null) { taskManager.scheduler.runTask(player, () -> { - userMessages.sendMessage(message, player, cannon); + userMessages.sendMessage(msg, player, cannon); SoundUtils.playErrorSound(cannon.getMuzzle()); }); } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java index 226f7644..867808a1 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java @@ -2,6 +2,7 @@ import at.pavlov.cannons.Cannons; import at.pavlov.cannons.hooks.BukkitHook; +import at.pavlov.cannons.hooks.movecraft.listener.TeleportPlayerHandler; import at.pavlov.cannons.hooks.movecraft.listener.CraftDetectListener; import at.pavlov.cannons.hooks.movecraft.listener.RotationListener; import at.pavlov.cannons.hooks.movecraft.listener.SinkListener; @@ -9,7 +10,6 @@ import at.pavlov.internal.Hook; import net.countercraft.movecraft.Movecraft; import org.bukkit.ChatColor; -import org.bukkit.event.HandlerList; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; @@ -42,6 +42,7 @@ public void onEnable() { pluginManager.registerEvents(new TranslationListener(), plugin); pluginManager.registerEvents(new RotationListener(), plugin); pluginManager.registerEvents(new SinkListener(), plugin); + pluginManager.registerEvents(new TeleportPlayerHandler(), plugin); plugin.logInfo(ChatColor.GREEN + enabledMessage()); } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TeleportPlayerHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TeleportPlayerHandler.java new file mode 100644 index 00000000..80e35144 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TeleportPlayerHandler.java @@ -0,0 +1,44 @@ +package at.pavlov.cannons.hooks.movecraft.listener; + +import at.pavlov.cannons.event.CannonBeforeCreateEvent; +import net.countercraft.movecraft.events.CraftTeleportEntityEvent; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import java.util.HashMap; +import java.util.UUID; + +public class TeleportPlayerHandler implements Listener { + private final HashMap playerCannonCooldown = new HashMap<>(); + + @EventHandler(ignoreCancelled = true) + private void handleTeleport(CraftTeleportEntityEvent event) { + Entity entity = event.getEntity(); + if (!(entity instanceof Player player)) { + return; + } + + long tickCooldown = event.getCraft().getTickCooldown() * 50L; + playerCannonCooldown.put( + player.getUniqueId(), + tickCooldown * 2 + System.currentTimeMillis() + ); + } + + @EventHandler(ignoreCancelled = true) + private void handleCreation(CannonBeforeCreateEvent event) { + UUID player = event.getPlayer(); + Long cooldown = playerCannonCooldown.get(player); + if (cooldown == null) return; + + if (System.currentTimeMillis() < cooldown) { + event.setCancelled(true); + event.setMessage(null); + return; + } + + playerCannonCooldown.remove(player); + } +} From 723d99c0e320003dde0fb18770859e0de976c513 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Wed, 1 Oct 2025 10:14:34 +0200 Subject: [PATCH 39/48] Optimize getBlock --- .../src/main/java/at/pavlov/cannons/cannon/Cannon.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java index 9d0e7a06..eb5e97b0 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java @@ -38,6 +38,7 @@ import me.vaan.schematiclib.base.schematic.OffsetSchematic; import me.vaan.schematiclib.base.schematic.OffsetSchematicImpl; import me.vaan.schematiclib.base.schematic.Schematic; +import me.vaan.schematiclib.file.block.FileBlock; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Effect; @@ -798,8 +799,8 @@ public boolean isCannonBlock(Block block) { } SchematicWorldProcessorImpl processor = SchematicWorldProcessorImpl.getProcessor(); + IBlock obtain = processor.registry().getBlock(block.getX(), block.getY(), block.getZ(), world); for (IBlock schemBlock : getOffsetSchematic().realBlocks()) { - IBlock obtain = processor.registry().getBlock(block.getX(), block.getY(), block.getZ(), world); if (obtain.matches(schemBlock)) { return true; } From 128f8d91a310cd82ed505ccf28bdff1de81cf4d6 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 2 Oct 2025 21:51:29 +0200 Subject: [PATCH 40/48] Optimize getting cannon from locations --- .../java/at/pavlov/cannons/cannon/Cannon.java | 24 +++++++++++++++++++ .../pavlov/cannons/cannon/CannonManager.java | 20 +++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java index eb5e97b0..0e32da86 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java @@ -34,6 +34,7 @@ import lombok.Getter; import lombok.Setter; import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.block.ICoord; import me.vaan.schematiclib.base.schematic.ConstantOffsetSchematic; import me.vaan.schematiclib.base.schematic.OffsetSchematic; import me.vaan.schematiclib.base.schematic.OffsetSchematicImpl; @@ -809,6 +810,29 @@ public boolean isCannonBlock(Block block) { return false; } + public boolean isCannonBlock(IBlock block, UUID blockWorld) { + UUID world = cannonPosition.getWorld(); + if (!world.equals(blockWorld)) { + return false; + } + + Vector offset = cannonPosition.getOffset(); + FileBlock offsetLessBlock = new FileBlock( + block.x() - offset.getBlockX(), + block.y() - offset.getBlockY(), + block.z() - offset.getBlockZ(), + block.key() + ); + + for (IBlock schemBlock : getOffsetSchematic().positions()) { + if (offsetLessBlock.matches(schemBlock)) { + return true; + } + } + + return false; + } + /** * return true if this block can be destroyed, false if it is protected * diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java index fa40ea7e..49e71524 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java @@ -7,7 +7,6 @@ import at.pavlov.cannons.config.Config; import at.pavlov.cannons.config.UserMessages; import at.pavlov.cannons.container.ItemHolder; -import at.pavlov.cannons.container.SimpleBlock; import at.pavlov.cannons.dao.AsyncTaskManager; import at.pavlov.cannons.dao.LoadWhitelistTask; import at.pavlov.cannons.event.CannonAfterCreateEvent; @@ -21,6 +20,7 @@ import com.google.common.base.Preconditions; import lombok.Getter; import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.namespace.NamespaceRegistry; import me.vaan.schematiclib.base.schematic.OffsetSchematic; import me.vaan.schematiclib.base.schematic.OffsetSchematicImpl; import me.vaan.schematiclib.base.schematic.Schematic; @@ -37,10 +37,12 @@ import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -436,9 +438,21 @@ public void dismantleCannonsInBox(Player player, Location center, int size) { */ public static HashSet getCannonsByLocations(List locations) { HashSet newCannonList = new HashSet<>(); + Map blocks = new HashMap<>(locations.size()); + NamespaceRegistry registry = SchematicWorldProcessorImpl.getProcessor().registry(); + for (Location loc : locations) { + UUID world = loc.getWorld().getUID(); + blocks.put(registry.getBlock( + loc.getBlockX(), + loc.getBlockY(), + loc.getBlockZ(), + world + ), world); + } + for (Cannon cannon : getCannonList().values()) { - for (Location loc : locations) { - if (cannon.isCannonBlock(loc.getBlock())) + for (var loc : blocks.entrySet()) { + if (cannon.isCannonBlock(loc.getKey(), loc.getValue())) newCannonList.add(cannon); } } From 6a955b17795b63ecf30841318bf3a0c4a727912c Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 2 Oct 2025 21:52:33 +0200 Subject: [PATCH 41/48] Get cannons on Detect and update them until release --- .../movecraft/MovecraftCannonTracker.java | 24 ++++++++++++++++++ .../hooks/movecraft/MovecraftHook.java | 6 +++-- .../listener/CraftDetectListener.java | 25 ++++++++----------- .../listener/CraftReleaseListener.java | 14 +++++++++++ ...ndler.java => PreventRecreateHandler.java} | 2 +- .../movecraft/listener/RotationListener.java | 4 +-- .../movecraft/listener/SinkListener.java | 4 ++- .../listener/TranslationListener.java | 5 +++- 8 files changed, 62 insertions(+), 22 deletions(-) create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftCannonTracker.java create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftReleaseListener.java rename cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/{TeleportPlayerHandler.java => PreventRecreateHandler.java} (95%) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftCannonTracker.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftCannonTracker.java new file mode 100644 index 00000000..79790152 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftCannonTracker.java @@ -0,0 +1,24 @@ +package at.pavlov.cannons.hooks.movecraft; + +import at.pavlov.cannons.cannon.Cannon; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public class MovecraftCannonTracker { + private static final Map> cannonMap = new HashMap<>(); + + public static Set getCannons(UUID uuid) { + return cannonMap.get(uuid); + } + + public static void setCannons(UUID craftId, Set cannons) { + cannonMap.put(craftId, cannons); + } + + public static void clearCannons(UUID craftId) { + cannonMap.remove(craftId); + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java index 867808a1..8fa0fdd0 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java @@ -2,7 +2,8 @@ import at.pavlov.cannons.Cannons; import at.pavlov.cannons.hooks.BukkitHook; -import at.pavlov.cannons.hooks.movecraft.listener.TeleportPlayerHandler; +import at.pavlov.cannons.hooks.movecraft.listener.CraftReleaseListener; +import at.pavlov.cannons.hooks.movecraft.listener.PreventRecreateHandler; import at.pavlov.cannons.hooks.movecraft.listener.CraftDetectListener; import at.pavlov.cannons.hooks.movecraft.listener.RotationListener; import at.pavlov.cannons.hooks.movecraft.listener.SinkListener; @@ -42,7 +43,8 @@ public void onEnable() { pluginManager.registerEvents(new TranslationListener(), plugin); pluginManager.registerEvents(new RotationListener(), plugin); pluginManager.registerEvents(new SinkListener(), plugin); - pluginManager.registerEvents(new TeleportPlayerHandler(), plugin); + pluginManager.registerEvents(new PreventRecreateHandler(), plugin); + pluginManager.registerEvents(new CraftReleaseListener(), plugin); plugin.logInfo(ChatColor.GREEN + enabledMessage()); } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftDetectListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftDetectListener.java index ed05c327..54dcaa4a 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftDetectListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftDetectListener.java @@ -1,16 +1,13 @@ package at.pavlov.cannons.hooks.movecraft.listener; import at.pavlov.cannons.Cannons; -import at.pavlov.cannons.Enum.BreakCause; import at.pavlov.cannons.cannon.Cannon; -import at.pavlov.cannons.cannon.CannonManager; +import at.pavlov.cannons.hooks.movecraft.MovecraftCannonTracker; import at.pavlov.cannons.hooks.movecraft.MovecraftUtils; import at.pavlov.cannons.hooks.movecraft.type.MaxCannonsEntry; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.craft.PlayerCraft; import net.countercraft.movecraft.craft.type.CraftType; import net.countercraft.movecraft.events.CraftDetectEvent; -import net.countercraft.movecraft.events.CraftSinkEvent; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -23,7 +20,7 @@ public class CraftDetectListener implements Listener { private static final Set notifyError = new HashSet<>(); - private static final Cannons cannon = Cannons.getPlugin(); + private static final Cannons plugin = Cannons.getPlugin(); @EventHandler public void onCraftDetect(CraftDetectEvent e) { @@ -32,13 +29,7 @@ public void onCraftDetect(CraftDetectEvent e) { if (notifyError.contains(type)) return; - if (!(craft instanceof PlayerCraft)) - return; - Set maxCannons = getCannonProperty(type); - if (maxCannons.isEmpty()) - return; // Return if empty set to improve performance - // Sum up counts of each cannon design Set cannons = MovecraftUtils.getCannons(craft); Map cannonCount = new HashMap<>(); @@ -51,8 +42,10 @@ public void onCraftDetect(CraftDetectEvent e) { // Check designs against maxCannons int size = craft.getOrigBlockCount(); for (var entry : maxCannons) { - if (!(entry instanceof MaxCannonsEntry max)) - throw new IllegalStateException("maxCannons must be a set of MaxCannonsEntry."); + if (!(entry instanceof MaxCannonsEntry max)) { + plugin.logSevere("maxCannons must be a set of MaxCannonsEntry."); + continue; + } var cannonName = max.getName(); var count = cannonCount.get(cannonName.toLowerCase()); @@ -67,11 +60,13 @@ public void onCraftDetect(CraftDetectEvent e) { + cannonName + ": " + error); }); } + + MovecraftCannonTracker.setCannons(craft.getUUID(), cannons); } private void printCannonCount(Map cannonCount) { for (var entry : cannonCount.entrySet()) { - cannon.logDebug("Cannon found: " + entry.getKey() + " | " + entry.getValue()); + plugin.logDebug("Cannon found: " + entry.getKey() + " | " + entry.getValue()); } } @@ -85,7 +80,7 @@ private Set getCannonProperty(CraftType type) { } } catch (Exception exception) { notifyError.add(type); - cannon.logSevere( + plugin.logSevere( "Failed to get maxCannons property from craft " + type.getStringProperty(CraftType.NAME) + " maxCannons won't be applied. - Cause: " + diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftReleaseListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftReleaseListener.java new file mode 100644 index 00000000..6e8dcf79 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftReleaseListener.java @@ -0,0 +1,14 @@ +package at.pavlov.cannons.hooks.movecraft.listener; + +import at.pavlov.cannons.hooks.movecraft.MovecraftCannonTracker; +import net.countercraft.movecraft.events.CraftReleaseEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class CraftReleaseListener implements Listener { + + @EventHandler + public void onCraftRelease(CraftReleaseEvent event) { + MovecraftCannonTracker.clearCannons(event.getCraft().getUUID()); + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TeleportPlayerHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/PreventRecreateHandler.java similarity index 95% rename from cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TeleportPlayerHandler.java rename to cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/PreventRecreateHandler.java index 80e35144..d77f20db 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TeleportPlayerHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/PreventRecreateHandler.java @@ -10,7 +10,7 @@ import java.util.HashMap; import java.util.UUID; -public class TeleportPlayerHandler implements Listener { +public class PreventRecreateHandler implements Listener { private final HashMap playerCannonCooldown = new HashMap<>(); @EventHandler(ignoreCancelled = true) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/RotationListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/RotationListener.java index f338d2fa..2003541a 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/RotationListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/RotationListener.java @@ -1,7 +1,7 @@ package at.pavlov.cannons.hooks.movecraft.listener; import at.pavlov.cannons.cannon.Cannon; -import at.pavlov.cannons.hooks.movecraft.MovecraftUtils; +import at.pavlov.cannons.hooks.movecraft.MovecraftCannonTracker; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftRotateEvent; import org.bukkit.event.EventHandler; @@ -17,7 +17,7 @@ public class RotationListener implements Listener { public void rotateListener(CraftRotateEvent e) { Craft craft = e.getCraft(); - Set cannons = MovecraftUtils.getCannons(craft); + Set cannons = MovecraftCannonTracker.getCannons(craft.getUUID()); if (cannons.isEmpty()) return; diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/SinkListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/SinkListener.java index d57fd694..ef23a162 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/SinkListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/SinkListener.java @@ -3,6 +3,7 @@ import at.pavlov.cannons.Enum.BreakCause; import at.pavlov.cannons.cannon.Cannon; import at.pavlov.cannons.cannon.CannonManager; +import at.pavlov.cannons.hooks.movecraft.MovecraftCannonTracker; import at.pavlov.cannons.hooks.movecraft.MovecraftUtils; import net.countercraft.movecraft.events.CraftSinkEvent; import org.bukkit.event.EventHandler; @@ -15,6 +16,7 @@ public class SinkListener implements Listener { @EventHandler public void onCraftSink(CraftSinkEvent event) { Set cannons = MovecraftUtils.getCannons(event.getCraft()); - cannons.forEach(cannon -> CannonManager.getInstance().removeCannon(cannon.getUID(), false, true, BreakCause.Explosion)); + MovecraftCannonTracker.clearCannons(event.getCraft().getUUID()); + cannons.forEach(cannon -> CannonManager.getInstance().removeCannon(cannon.getUID(), true, true, BreakCause.Explosion)); } } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TranslationListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TranslationListener.java index 35fa1ccf..4e619ae5 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TranslationListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/TranslationListener.java @@ -1,6 +1,7 @@ package at.pavlov.cannons.hooks.movecraft.listener; import at.pavlov.cannons.cannon.Cannon; +import at.pavlov.cannons.hooks.movecraft.MovecraftCannonTracker; import at.pavlov.cannons.hooks.movecraft.MovecraftUtils; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.events.CraftTranslateEvent; @@ -21,7 +22,9 @@ public void translateListener(CraftTranslateEvent e) { if (v == null) return; - Set cannons = MovecraftUtils.getCannons(e.getCraft()); + Set cannons = MovecraftCannonTracker.getCannons(e.getCraft().getUUID()); + if (cannons == null) return; //for sinking ships + if (cannons.isEmpty()) return; for (Cannon c : cannons) { From ba8f5d9038b17cf7c316813209cdde9cb922502f Mon Sep 17 00:00:00 2001 From: Intybyte Date: Sun, 26 Oct 2025 18:21:08 +0100 Subject: [PATCH 42/48] Add nexo support --- cannons-bukkit/pom.xml | 23 ++++++- .../namespace/NexoNamespaceHandler.java | 62 +++++++++++++++++++ .../world/SchematicWorldProcessorImpl.java | 7 +++ cannons-bukkit/src/main/resources/plugin.yml | 1 + 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 440a200c..1a90cdf3 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -69,6 +69,10 @@ matteodev https://maven.devs.beer/ + + nexo + https://repo.nexomc.com/releases + @@ -134,6 +138,23 @@ 4.0.10 provided + + com.nexomc + nexo + 1.12.1-dev + provided + + + + dev.triumphteam + triumph-gui + + + net.byteflux + libby-bukkit + + + @@ -210,7 +231,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.14.1 ${java.source} ${java.target} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java new file mode 100644 index 00000000..93b4e7ae --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java @@ -0,0 +1,62 @@ +package at.pavlov.cannons.schematic.namespace; + +import com.nexomc.nexo.api.NexoBlocks; +import com.nexomc.nexo.api.NexoFurniture; +import com.nexomc.nexo.mechanics.custom_block.CustomBlockMechanic; +import com.nexomc.nexo.mechanics.custom_block.CustomBlockRegistry; +import me.vaan.schematiclib.base.block.BlockKey; +import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.namespace.NamespaceHandler; +import me.vaan.schematiclib.file.block.FileBlock; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; + +import java.util.UUID; + +public class NexoNamespaceHandler implements NamespaceHandler { + @Override + public void place(IBlock iBlock, UUID world) { + String item_id = iBlock.key().key().replace('$', ':'); + Location loc = new Location(Bukkit.getWorld(world), iBlock.x(), iBlock.y(), iBlock.z()); + NexoBlocks.place(item_id, loc); + } + + @Override + public IBlock get(int x, int y, int z, UUID world) { + Block block = new Location(Bukkit.getWorld(world), x, y, z).getBlock(); + + CustomBlockMechanic cbm = NexoBlocks.customBlockMechanic(block); + if (cbm == null) return null; + + String item_id = cbm.getItemID().replace(':', '$'); + + return new FileBlock(x, y, z, new BlockKey("nexo", item_id)); + } + + @Override + public void destroy(IBlock iBlock, UUID world) { + + // 0 idea how to use this, but maybe this is what I am looking for + //CustomBlockRegistry.INSTANCE.getMechanic("ee").getType().removeWorldEdit(); + Location loc = new Location(Bukkit.getWorld(world), iBlock.x(), iBlock.y(), iBlock.z()); + NexoBlocks.remove(loc); + } + + @Override + public void breakNaturally(IBlock iBlock, UUID world) { + Location loc = new Location(Bukkit.getWorld(world), iBlock.x(), iBlock.y(), iBlock.z()); + NexoBlocks.remove(loc, null, true); + } + + @Override + public BlockKey toMaterial(BlockKey blockKey) { + String item_id = blockKey.key().replace('$', ':'); + BlockData data = NexoBlocks.blockData(item_id); + NamespacedKey key = data.getMaterial().getKey(); + + return BlockKey.mc(key.getKey()); + } +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java index 9195eac9..ecbb6ba5 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java @@ -3,6 +3,7 @@ import at.pavlov.cannons.schematic.block.BlockImpl; import at.pavlov.cannons.schematic.namespace.ItemsAdderNamespaceHandler; import at.pavlov.cannons.schematic.namespace.MinecraftNamespaceHandler; +import at.pavlov.cannons.schematic.namespace.NexoNamespaceHandler; import at.pavlov.cannons.schematic.namespace.SlimefunNamespaceHandler; import lombok.Getter; import me.vaan.schematiclib.base.block.IBlock; @@ -55,6 +56,12 @@ private SchematicWorldProcessorImpl registerAll() { new ItemsAdderNamespaceHandler() ); + registerReflectionNamespace( + "nexo", + "com.nexomc.nexo.api.NexoBlocks", + new NexoNamespaceHandler() + ); + return this; } } diff --git a/cannons-bukkit/src/main/resources/plugin.yml b/cannons-bukkit/src/main/resources/plugin.yml index e8801dd5..cd1cb85f 100644 --- a/cannons-bukkit/src/main/resources/plugin.yml +++ b/cannons-bukkit/src/main/resources/plugin.yml @@ -10,6 +10,7 @@ softdepend: - PlaceholderAPI - Slimefun - ItemsAdder + - Nexo authors: [DerPavlov, Vaan1310] description: Fire block build cannons and smash your enemies folia-supported: true From f062fcf6ef21c23a6ebf664f2e8674092ea682e2 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Mon, 27 Oct 2025 10:21:29 +0100 Subject: [PATCH 43/48] One block furnitures work too --- .../namespace/NexoNamespaceHandler.java | 50 +++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java index 93b4e7ae..3e7734f3 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java @@ -3,7 +3,7 @@ import com.nexomc.nexo.api.NexoBlocks; import com.nexomc.nexo.api.NexoFurniture; import com.nexomc.nexo.mechanics.custom_block.CustomBlockMechanic; -import com.nexomc.nexo.mechanics.custom_block.CustomBlockRegistry; +import com.nexomc.nexo.mechanics.furniture.FurnitureMechanic; import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; import me.vaan.schematiclib.base.namespace.NamespaceHandler; @@ -12,6 +12,7 @@ import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import java.util.UUID; @@ -21,7 +22,12 @@ public class NexoNamespaceHandler implements NamespaceHandler { public void place(IBlock iBlock, UUID world) { String item_id = iBlock.key().key().replace('$', ':'); Location loc = new Location(Bukkit.getWorld(world), iBlock.x(), iBlock.y(), iBlock.z()); - NexoBlocks.place(item_id, loc); + + if (NexoBlocks.isCustomBlock(item_id)) NexoBlocks.place(item_id, loc); + + FurnitureMechanic fm = getOneBlockFurniture(item_id); + if (fm == null) return; + NexoFurniture.place(item_id, loc, 0f, BlockFace.NORTH); } @Override @@ -29,11 +35,19 @@ public IBlock get(int x, int y, int z, UUID world) { Block block = new Location(Bukkit.getWorld(world), x, y, z).getBlock(); CustomBlockMechanic cbm = NexoBlocks.customBlockMechanic(block); - if (cbm == null) return null; + if (cbm != null) { + String item_id = cbm.getItemID().replace(':', '$'); + return new FileBlock(x, y, z, new BlockKey("nexo", item_id)); + } - String item_id = cbm.getItemID().replace(':', '$'); + FurnitureMechanic fm = NexoFurniture.furnitureMechanic(block); + if (fm != null && fm.getHitbox().getBarriers().size() == 1) { + String item_id = fm.getItemID().replace(':', '$'); + return new FileBlock(x, y, z, new BlockKey("nexo", item_id)); + } + + return null; - return new FileBlock(x, y, z, new BlockKey("nexo", item_id)); } @Override @@ -42,21 +56,39 @@ public void destroy(IBlock iBlock, UUID world) { // 0 idea how to use this, but maybe this is what I am looking for //CustomBlockRegistry.INSTANCE.getMechanic("ee").getType().removeWorldEdit(); Location loc = new Location(Bukkit.getWorld(world), iBlock.x(), iBlock.y(), iBlock.z()); - NexoBlocks.remove(loc); + Block block = loc.getBlock(); + if (NexoBlocks.isCustomBlock(block)) NexoBlocks.remove(loc); + if (NexoFurniture.isFurniture(loc)) NexoFurniture.remove(loc); } @Override public void breakNaturally(IBlock iBlock, UUID world) { Location loc = new Location(Bukkit.getWorld(world), iBlock.x(), iBlock.y(), iBlock.z()); - NexoBlocks.remove(loc, null, true); + Block block = loc.getBlock(); + if (NexoBlocks.isCustomBlock(block)) NexoBlocks.remove(loc, null, true); + if (NexoFurniture.isFurniture(loc)) NexoFurniture.remove(loc); } + private static final BlockKey BARRIER = BlockKey.mc("barrier"); @Override public BlockKey toMaterial(BlockKey blockKey) { String item_id = blockKey.key().replace('$', ':'); BlockData data = NexoBlocks.blockData(item_id); - NamespacedKey key = data.getMaterial().getKey(); + if (data != null) { + NamespacedKey key = data.getMaterial().getKey(); + return BlockKey.mc(key.getKey()); + } + + if (NexoFurniture.isFurniture(item_id)) return BARRIER; + + throw new UnsupportedOperationException(); + } + + private FurnitureMechanic getOneBlockFurniture(String id) { + FurnitureMechanic fm = NexoFurniture.furnitureMechanic(id); + if (fm == null) return null; + if (fm.getHitbox().getBarriers().size() != 1) return null; - return BlockKey.mc(key.getKey()); + return fm; } } From 7fab949655b02b287c06061f4ac8cdc07a24a843 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 30 Oct 2025 15:22:51 +0100 Subject: [PATCH 44/48] Faster schematic implementations --- .../java/at/pavlov/cannons/cannon/Cannon.java | 21 +++++++++++-------- .../pavlov/cannons/cannon/CannonManager.java | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java index 0e32da86..9bfcd38e 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java @@ -33,13 +33,13 @@ import com.google.common.base.Preconditions; import lombok.Getter; import lombok.Setter; +import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; -import me.vaan.schematiclib.base.block.ICoord; -import me.vaan.schematiclib.base.schematic.ConstantOffsetSchematic; import me.vaan.schematiclib.base.schematic.OffsetSchematic; import me.vaan.schematiclib.base.schematic.OffsetSchematicImpl; import me.vaan.schematiclib.base.schematic.Schematic; import me.vaan.schematiclib.file.block.FileBlock; +import me.vaan.schematiclib.file.block.FileCoord; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Effect; @@ -782,7 +782,7 @@ public OffsetSchematic getOffsetSchematic() { off.getBlockX(), off.getBlockY(), off.getBlockZ(), - schematic.positions() + schematic ); } @@ -800,14 +800,17 @@ public boolean isCannonBlock(Block block) { } SchematicWorldProcessorImpl processor = SchematicWorldProcessorImpl.getProcessor(); + OffsetSchematic offsetSchematic = getOffsetSchematic(); IBlock obtain = processor.registry().getBlock(block.getX(), block.getY(), block.getZ(), world); - for (IBlock schemBlock : getOffsetSchematic().realBlocks()) { - if (obtain.matches(schemBlock)) { - return true; - } - } + BlockKey schemBlock = offsetSchematic.blockMap().get( + new FileCoord( + block.getX() - offsetSchematic.x(), + block.getY() - offsetSchematic.y(), + block.getZ() - offsetSchematic.z() + ) + ); - return false; + return obtain.key().equals(schemBlock); } public boolean isCannonBlock(IBlock block, UUID blockWorld) { diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java index 49e71524..8b05fab2 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java @@ -709,7 +709,7 @@ private Cannon checkCannon(Location cannonBlock, UUID owner) { offset.getBlockX(), offset.getBlockY(), offset.getBlockZ(), - schem.positions() + schem ); boolean matches = processor.matches(offsetSchematic, world.getUID()); From a6bd9819afcdd8e46b02281145176442d18e2f69 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 30 Oct 2025 15:23:04 +0100 Subject: [PATCH 45/48] Fix and move dependencies --- api-internal/pom.xml | 2 +- cannons-bukkit/pom.xml | 48 ++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/api-internal/pom.xml b/api-internal/pom.xml index 39cfaa02..0daeb227 100644 --- a/api-internal/pom.xml +++ b/api-internal/pom.xml @@ -31,7 +31,7 @@ com.github.Intybyte SchematicLib - 6b6ddd9a83 + d669292866 org.jetbrains diff --git a/cannons-bukkit/pom.xml b/cannons-bukkit/pom.xml index 1a90cdf3..b397f32f 100644 --- a/cannons-bukkit/pom.xml +++ b/cannons-bukkit/pom.xml @@ -131,31 +131,6 @@ compile - - - dev.lone - api-itemsadder - 4.0.10 - provided - - - com.nexomc - nexo - 1.12.1-dev - provided - - - - dev.triumphteam - triumph-gui - - - net.byteflux - libby-bukkit - - - - net.milkbowl.vault @@ -189,6 +164,29 @@ RC-37 provided + + dev.lone + api-itemsadder + 4.0.10 + provided + + + com.nexomc + nexo + 1.12.1-dev + provided + + + + dev.triumphteam + triumph-gui + + + net.byteflux + libby-bukkit + + + From 18d11ab9338dc08653b7adc0077a877ddec1bb97 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Thu, 30 Oct 2025 15:23:18 +0100 Subject: [PATCH 46/48] Fix NexoNamespaceHandler --- .../schematic/namespace/Initialize.java | 5 ++ .../namespace/NexoNamespaceHandler.java | 52 ++++++++++++++++++- .../world/SchematicWorldProcessorImpl.java | 5 ++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/Initialize.java diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/Initialize.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/Initialize.java new file mode 100644 index 00000000..11f029b2 --- /dev/null +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/Initialize.java @@ -0,0 +1,5 @@ +package at.pavlov.cannons.schematic.namespace; + +public interface Initialize { + void init(); +} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java index 3e7734f3..93e35340 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java @@ -1,7 +1,15 @@ package at.pavlov.cannons.schematic.namespace; +import at.pavlov.cannons.Aiming; +import at.pavlov.cannons.Cannons; +import at.pavlov.cannons.Enum.BreakCause; +import at.pavlov.cannons.cannon.Cannon; +import at.pavlov.cannons.cannon.CannonManager; +import at.pavlov.cannons.cannon.DesignStorage; +import at.pavlov.cannons.utils.CannonSelector; import com.nexomc.nexo.api.NexoBlocks; import com.nexomc.nexo.api.NexoFurniture; +import com.nexomc.nexo.api.events.furniture.NexoFurnitureBreakEvent; import com.nexomc.nexo.mechanics.custom_block.CustomBlockMechanic; import com.nexomc.nexo.mechanics.furniture.FurnitureMechanic; import me.vaan.schematiclib.base.block.BlockKey; @@ -14,10 +22,22 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; import java.util.UUID; -public class NexoNamespaceHandler implements NamespaceHandler { +public class NexoNamespaceHandler implements NamespaceHandler, Listener, Initialize { + @Override + public void init() { + Cannons pl = Cannons.getPlugin(); + // furnitures aren't handled by block break + Bukkit.getPluginManager().registerEvents(this, pl); + // nexo block resolution requires some time first, so rerun load + Bukkit.getScheduler().runTaskLater(pl, DesignStorage.getInstance()::loadCannonDesigns, 5L); + } + @Override public void place(IBlock iBlock, UUID world) { String item_id = iBlock.key().key().replace('$', ':'); @@ -69,7 +89,7 @@ public void breakNaturally(IBlock iBlock, UUID world) { if (NexoFurniture.isFurniture(loc)) NexoFurniture.remove(loc); } - private static final BlockKey BARRIER = BlockKey.mc("barrier"); + private static final BlockKey BARRIER = BlockKey.mc("air"); @Override public BlockKey toMaterial(BlockKey blockKey) { String item_id = blockKey.key().replace('$', ':'); @@ -91,4 +111,32 @@ private FurnitureMechanic getOneBlockFurniture(String id) { return fm; } + + @EventHandler(ignoreCancelled = true) + private void onFurnitureBreak(NexoFurnitureBreakEvent event) { + if (event.getMechanic().getHitbox().getBarriers().size() != 1) return; + + CannonManager cannonManager = CannonManager.getInstance(); + Cannons plugin = Cannons.getPlugin(); + + Location location = event.getBaseEntity().getLocation().getBlock().getLocation(); + Cannon cannon = cannonManager.getCannonFromStorage(location); + + if (cannon == null) { + return; + } + + Cannon aimingCannon = null; + Player player = event.getPlayer(); + if (Aiming.getInstance().isInAimingMode(player.getUniqueId())) + aimingCannon = Aiming.getInstance().getCannonInAimingMode(player); + + if (!cannon.equals(aimingCannon) && !CannonSelector.getInstance().isSelectingMode(player)) { + cannonManager.removeCannon(cannon, false, true, BreakCause.PlayerBreak); + plugin.logDebug("cannon broken: " + location); + } else { + event.setCancelled(true); + plugin.logDebug("cancelled cannon destruction: " + location); + } + } } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java index ecbb6ba5..ad97d6bb 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/world/SchematicWorldProcessorImpl.java @@ -1,6 +1,7 @@ package at.pavlov.cannons.schematic.world; import at.pavlov.cannons.schematic.block.BlockImpl; +import at.pavlov.cannons.schematic.namespace.Initialize; import at.pavlov.cannons.schematic.namespace.ItemsAdderNamespaceHandler; import at.pavlov.cannons.schematic.namespace.MinecraftNamespaceHandler; import at.pavlov.cannons.schematic.namespace.NexoNamespaceHandler; @@ -36,6 +37,10 @@ public void registerReflectionNamespace(String namespace, String classToFind, Na return; } + if (handler instanceof Initialize initialize) { + initialize.init(); + } + registry.registerNamespaceHandler(namespace, handler); } From 4afaf72cc64c3ecdc519a453876f4194d2e2f018 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Sat, 15 Nov 2025 15:48:59 +0100 Subject: [PATCH 47/48] I am not gonna support custom movements, but well... I added it to the SchematicLib already so make the move handler empty --- api-internal/pom.xml | 2 +- .../schematic/namespace/ItemsAdderNamespaceHandler.java | 6 ++++++ .../schematic/namespace/MinecraftNamespaceHandler.java | 5 +++++ .../cannons/schematic/namespace/NexoNamespaceHandler.java | 6 ++++++ .../schematic/namespace/SlimefunNamespaceHandler.java | 6 ++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/api-internal/pom.xml b/api-internal/pom.xml index 0daeb227..37b6cda6 100644 --- a/api-internal/pom.xml +++ b/api-internal/pom.xml @@ -31,7 +31,7 @@ com.github.Intybyte SchematicLib - d669292866 + f420e46a34 org.jetbrains diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/ItemsAdderNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/ItemsAdderNamespaceHandler.java index 7fa0f724..c32c99b9 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/ItemsAdderNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/ItemsAdderNamespaceHandler.java @@ -5,6 +5,7 @@ import dev.lone.itemsadder.api.CustomBlock; import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.block.ICoord; import me.vaan.schematiclib.base.namespace.NamespaceHandler; import me.vaan.schematiclib.file.block.FileBlock; import org.bukkit.Bukkit; @@ -66,6 +67,11 @@ public void breakNaturally(IBlock iBlock, UUID uuid) { destroy(iBlock, uuid); } + @Override + public void move(ICoord from, ICoord to, BlockKey blockKey) { + + } + @Override public BlockKey toMaterial(BlockKey blockKey) { String realKey = blockKey.key().replace('$', ':'); diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java index 02932dc9..a63997fe 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/MinecraftNamespaceHandler.java @@ -4,6 +4,7 @@ import at.pavlov.cannons.schematic.block.BlockImpl; import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.block.ICoord; import me.vaan.schematiclib.base.namespace.NamespaceHandler; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -49,6 +50,10 @@ public void breakNaturally(IBlock iBlock, UUID uuid) { ).breakNaturally(); } + // no internal state to move + @Override + public void move(ICoord iCoord, ICoord iCoord1, BlockKey blockKey) {} + // should be unused @Override public BlockKey toMaterial(BlockKey blockKey) { diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java index 93e35340..48ba95d5 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/NexoNamespaceHandler.java @@ -14,6 +14,7 @@ import com.nexomc.nexo.mechanics.furniture.FurnitureMechanic; import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.block.ICoord; import me.vaan.schematiclib.base.namespace.NamespaceHandler; import me.vaan.schematiclib.file.block.FileBlock; import org.bukkit.Bukkit; @@ -89,6 +90,11 @@ public void breakNaturally(IBlock iBlock, UUID world) { if (NexoFurniture.isFurniture(loc)) NexoFurniture.remove(loc); } + @Override + public void move(ICoord from, ICoord to, BlockKey blockKey) { + + } + private static final BlockKey BARRIER = BlockKey.mc("air"); @Override public BlockKey toMaterial(BlockKey blockKey) { diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java index e155bb24..184ade85 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/schematic/namespace/SlimefunNamespaceHandler.java @@ -8,6 +8,7 @@ import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; import me.vaan.schematiclib.base.block.BlockKey; import me.vaan.schematiclib.base.block.IBlock; +import me.vaan.schematiclib.base.block.ICoord; import me.vaan.schematiclib.base.namespace.NamespaceHandler; import me.vaan.schematiclib.file.block.FileBlock; import org.bukkit.Bukkit; @@ -119,6 +120,11 @@ public void breakNaturally(IBlock iBlock, UUID uuid) { location.getBlock().setType(Material.AIR); } + @Override + public void move(ICoord from, ICoord to, BlockKey blockKey) { + + } + @Override public BlockKey toMaterial(BlockKey blockKey) { SlimefunItem sfItem = SlimefunItem.getById(blockKey.key().toUpperCase()); From 51eb1c0924b60baa2f8b2ef54eb6ad29f4493069 Mon Sep 17 00:00:00 2001 From: Intybyte Date: Tue, 20 Jan 2026 22:10:54 +0100 Subject: [PATCH 48/48] Merge fix --- .../java/at/pavlov/cannons/cannon/Cannon.java | 46 ++++++++++++++++++- .../pavlov/cannons/cannon/CannonBlocks.java | 46 ------------------- .../pavlov/cannons/cannon/CannonManager.java | 4 +- .../hooks/movecraft/MovecraftHook.java | 2 - .../listener/CraftDetectListener.java | 6 ++- .../listener/CraftReleaseListener.java | 14 ------ .../movecraft/listener/ReleaseListener.java | 7 ++- .../cannons/listener/BlockListener.java | 1 - .../cannons/listener/EntityListener.java | 1 - .../at/pavlov/cannons/utils/EventUtils.java | 3 +- 10 files changed, 57 insertions(+), 73 deletions(-) delete mode 100644 cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftReleaseListener.java diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java index 56d667ed..9aad30f2 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/Cannon.java @@ -97,7 +97,6 @@ public Cannon(CannonDesign design, UUID world, Vector cannonOffset, BlockFace ca this.design = design; this.cannonPosition = new CannonPosition(cannonDirection, cannonOffset, world, false, noVelocity.clone()); - Schematic schematic = design.getSchematicMap().get(cannonPosition.getCannonDirection()); boolean noFee = design.getEconomyBuildingCost() instanceof EmptyExchanger; this.mainData = new CannonMainData( UUID.randomUUID(),null, noFee, owner, true); @@ -765,6 +764,51 @@ public void hide() { ); } + private Vector min = null; + public Vector getMin() { + if (min != null) return min; + calculateMaxMin(); + return min; + } + + private Vector max = null; + public Vector getMax() { + if (max != null) return max; + calculateMaxMin(); + return max; + } + + private void calculateMaxMin() { + Schematic schematic = design.getSchematicMap().get(cannonPosition.getCannonDirection()); + List positions = schematic.positions(); + IBlock zero = positions.get(0); + Vector minT = new Vector(zero.x(), zero.y(), zero.z()); + Vector maxT = minT.clone(); + + for (var block : positions) { + minT.setX(Math.min(minT.getX(), block.x())); + minT.setY(Math.min(minT.getY(), block.y())); + minT.setZ(Math.min(minT.getZ(), block.z())); + + maxT.setX(Math.max(maxT.getX(), block.x())); + maxT.setY(Math.max(maxT.getY(), block.y())); + maxT.setZ(Math.max(maxT.getZ(), block.z())); + } + + min = minT; + max = maxT; + } + + private double diagonal = -1; + public double getDiagonal() { + if (diagonal < 0) { + calculateMaxMin(); + diagonal = max.distance(min); + } + + return diagonal; + } + /** * breaks all cannon blocks of the cannon diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonBlocks.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonBlocks.java index 75add2b5..4f920dd4 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonBlocks.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonBlocks.java @@ -18,7 +18,6 @@ public class CannonBlocks { private Vector rotationCenter; //center off all rotation blocks private Vector muzzle; //center off all muzzle blocks - spawing Vector for snowball - private ArrayList allCannonBlocks = new ArrayList<>(); private ArrayList barrelBlocks = new ArrayList<>(); private ArrayList chestsAndSigns = new ArrayList<>(); private ArrayList redstoneTorches = new ArrayList<>(); @@ -86,49 +85,4 @@ public void addFiringIndicator(Vector add) { public void addDestructibleBlocks(Vector add) { this.destructibleBlocks.add(add); } - - - private Vector min = null; - public Vector getMin() { - if (min != null) return min; - calculateMaxMin(); - return min; - } - - private Vector max = null; - public Vector getMax() { - if (max != null) return max; - calculateMaxMin(); - return max; - } - - private void calculateMaxMin() { - Vector minT = allCannonBlocks.get(0).toVector(); - Vector maxT = minT.clone(); - - for (var block : allCannonBlocks) { - Vector vec = block.toVector(); - - minT.setX(Math.min(minT.getX(), vec.getX())); - minT.setY(Math.min(minT.getY(), vec.getY())); - minT.setZ(Math.min(minT.getZ(), vec.getZ())); - - maxT.setX(Math.max(maxT.getX(), vec.getX())); - maxT.setY(Math.max(maxT.getY(), vec.getY())); - maxT.setZ(Math.max(maxT.getZ(), vec.getZ())); - } - - min = minT; - max = maxT; - } - - private double diagonal = -1; - public double getDiagonal() { - if (diagonal < 0) { - calculateMaxMin(); - diagonal = max.distance(min); - } - - return diagonal; - } } \ No newline at end of file diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java index fa8ca0d1..0690e249 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/cannon/CannonManager.java @@ -506,9 +506,7 @@ public static Cannon getCannon(String cannonName) { public Cannon getCannonFromStorage(Location loc) { Vector vector = loc.toVector(); for (Cannon cannon : cannonList.values()) { - var design = cannon.getCannonDesign(); - var cannonBlocks = design.getCannonBlockMap().get(cannon.getCannonDirection()); - double diagonal = cannonBlocks.getDiagonal(); + double diagonal = cannon.getDiagonal(); if (diagonal < 0 || vector.distance(cannon.getOffset()) >= diagonal) continue; if (cannon.isCannonBlock(loc.getBlock())) { diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java index dd83e879..5807d1e0 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/MovecraftHook.java @@ -2,7 +2,6 @@ import at.pavlov.cannons.Cannons; import at.pavlov.cannons.hooks.BukkitHook; -import at.pavlov.cannons.hooks.movecraft.listener.CraftReleaseListener; import at.pavlov.cannons.hooks.movecraft.listener.PreventRecreateHandler; import at.pavlov.cannons.hooks.movecraft.listener.CraftDetectListener; import at.pavlov.cannons.hooks.movecraft.listener.ReleaseListener; @@ -45,7 +44,6 @@ public void onEnable() { pluginManager.registerEvents(new RotationListener(), plugin); pluginManager.registerEvents(new SinkListener(), plugin); pluginManager.registerEvents(new PreventRecreateHandler(), plugin); - pluginManager.registerEvents(new CraftReleaseListener(), plugin); pluginManager.registerEvents(new ReleaseListener(), plugin); plugin.logInfo(ChatColor.GREEN + enabledMessage()); } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftDetectListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftDetectListener.java index 800d3643..708eb7a7 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftDetectListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftDetectListener.java @@ -3,6 +3,7 @@ import at.pavlov.cannons.Cannons; import at.pavlov.cannons.cannon.Cannon; import at.pavlov.cannons.cannon.CannonDesign; +import at.pavlov.cannons.hooks.movecraft.MovecraftCannonTracker; import at.pavlov.cannons.hooks.movecraft.MovecraftUtils; import at.pavlov.cannons.hooks.movecraft.type.CannonCheck; import at.pavlov.cannons.hooks.movecraft.type.properties.CannonProperties; @@ -37,10 +38,11 @@ public void onCraftDetect(CraftDetectEvent e) { if (checkMass(e, cannons, type)) return; - boolean useShip = CannonProperties.USE_SHIP_ANGLES.get(type) == Boolean.TRUE; - if (useShip) { + if (CannonProperties.USE_SHIP_ANGLES.get(type) == Boolean.TRUE) { cannons.forEach(it -> it.setOnShip(true)); } + + MovecraftCannonTracker.setCannons(craft.getUUID(), cannons); } private boolean checkMass(CraftDetectEvent e, Set cannons, CraftType type) { diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftReleaseListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftReleaseListener.java deleted file mode 100644 index 6e8dcf79..00000000 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/CraftReleaseListener.java +++ /dev/null @@ -1,14 +0,0 @@ -package at.pavlov.cannons.hooks.movecraft.listener; - -import at.pavlov.cannons.hooks.movecraft.MovecraftCannonTracker; -import net.countercraft.movecraft.events.CraftReleaseEvent; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; - -public class CraftReleaseListener implements Listener { - - @EventHandler - public void onCraftRelease(CraftReleaseEvent event) { - MovecraftCannonTracker.clearCannons(event.getCraft().getUUID()); - } -} diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/ReleaseListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/ReleaseListener.java index 9b1bbfae..bf6e249f 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/ReleaseListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/hooks/movecraft/listener/ReleaseListener.java @@ -1,15 +1,20 @@ package at.pavlov.cannons.hooks.movecraft.listener; +import at.pavlov.cannons.hooks.movecraft.MovecraftCannonTracker; import at.pavlov.cannons.hooks.movecraft.MovecraftUtils; import net.countercraft.movecraft.events.CraftReleaseEvent; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import java.util.UUID; + public class ReleaseListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onRelease(CraftReleaseEvent event) { - MovecraftUtils.getCannons(event.getCraft()).forEach(it -> it.setOnShip(false)); + UUID id = event.getCraft().getUUID(); + MovecraftCannonTracker.getCannons(id).forEach(it -> it.setOnShip(false)); + MovecraftCannonTracker.clearCannons(id); } } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/BlockListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/BlockListener.java index e1ea3e3d..8a47a94f 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/BlockListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/BlockListener.java @@ -58,7 +58,6 @@ public void blockExplodeEvent(BlockExplodeEvent event) { } //search for destroyed cannons - event.blockList().removeIf(it -> it.getType().isAir()); EventUtils.handleExplosion(event.blockList()); } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/EntityListener.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/EntityListener.java index 0d5137c2..6c92c78b 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/EntityListener.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/listener/EntityListener.java @@ -49,7 +49,6 @@ public void onEntityExplode(EntityExplodeEvent event) { return; } - event.blockList().removeIf(it -> it.getType().isAir()); EventUtils.handleExplosion(event.blockList()); } diff --git a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java index 38414571..283946bc 100644 --- a/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java +++ b/cannons-bukkit/src/main/java/at/pavlov/cannons/utils/EventUtils.java @@ -19,6 +19,7 @@ private EventUtils() {} * @param blocklist list of blocks involved in the event */ public static void handleExplosion(List blocklist) { + blocklist.removeIf(it -> it.getType().isAir()); CannonManager cannonManager = CannonManager.getInstance(); HashSet remove = new HashSet<>(); HashMap cannonHashMap = new HashMap<>(); @@ -28,8 +29,6 @@ public static void handleExplosion(List blocklist) { if (block == null) continue; Location location = block.getLocation(); - if (block.getType().isAir()) continue; - Cannon cannon = cannonManager.getCannonFromStorage(location); // if it is a cannon block if (cannon == null) {