diff --git a/BedWars.iml b/BedWars.iml
index 1fd1d00..f570be0 100644
--- a/BedWars.iml
+++ b/BedWars.iml
@@ -33,5 +33,13 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 4273aeb..e266c31 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,14 @@
sonatype
https://oss.sonatype.org/content/groups/public/
+
+ fawe-repo
+ https://ci.athion.net/job/FastAsyncWorldEdit/ws/mvn/
+
+
+ placeholderapi
+ https://repo.extendedclip.com/content/repositories/placeholderapi/
+
@@ -98,5 +106,29 @@
provided
+
+
+ com.sk89q
+ worldedit
+ 6.0.0-SNAPSHOT
+ provided
+
+
+
+
+ com.boydti
+ fawe-api
+ latest
+ provided
+
+
+
+
+ me.clip
+ placeholderapi
+ 2.10.9
+ provided
+
+
diff --git a/src/main/java/rip/tilly/bedwars/commands/arena/ArenaCommand.java b/src/main/java/rip/tilly/bedwars/commands/arena/ArenaCommand.java
new file mode 100644
index 0000000..d9b469d
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/commands/arena/ArenaCommand.java
@@ -0,0 +1,49 @@
+package rip.tilly.bedwars.commands.arena;
+
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import rip.tilly.bedwars.BedWars;
+import rip.tilly.bedwars.utils.CC;
+
+public class ArenaCommand implements CommandExecutor {
+
+ private BedWars plugin = BedWars.getInstance();
+
+ public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ Player player = (Player) sender;
+
+ if (!player.hasPermission("bedwars.admin")) {
+ player.sendMessage(CC.translate("&cNo permission"));
+
+ return true;
+ }
+
+ if (args.length == 0) {
+ player.sendMessage(CC.translate("&cUsage:"));
+ player.sendMessage(CC.translate(" &c/arena"));
+ player.sendMessage(CC.translate(" &c/arena manage (Opens arena manage menu)"));
+ player.sendMessage(CC.translate(" &c/arena create "));
+ player.sendMessage(CC.translate(" &c/arena icon "));
+ player.sendMessage(CC.translate(" &c/arena enable "));
+ player.sendMessage(CC.translate(" &c/arena disable "));
+ player.sendMessage(CC.translate(" &c/arena a "));
+ player.sendMessage(CC.translate(" &c/arena b "));
+ player.sendMessage(CC.translate(" &c/arena min "));
+ player.sendMessage(CC.translate(" &c/arena max "));
+ player.sendMessage(CC.translate(" &c/arena teamAmin "));
+ player.sendMessage(CC.translate(" &c/arena teamAmax "));
+ player.sendMessage(CC.translate(" &c/arena teamBmin "));
+ player.sendMessage(CC.translate(" &c/arena teamBmax "));
+ player.sendMessage(CC.translate(" &c/arena deadzone "));
+ player.sendMessage(CC.translate(" &c/arena buildmax "));
+ } else {
+ switch (args[0].toLowerCase()) {
+
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/managers/CommandManager.java b/src/main/java/rip/tilly/bedwars/managers/CommandManager.java
index c6313c5..074b984 100644
--- a/src/main/java/rip/tilly/bedwars/managers/CommandManager.java
+++ b/src/main/java/rip/tilly/bedwars/managers/CommandManager.java
@@ -1,6 +1,7 @@
package rip.tilly.bedwars.managers;
import rip.tilly.bedwars.BedWars;
+import rip.tilly.bedwars.commands.arena.ArenaCommand;
import rip.tilly.bedwars.commands.level.LevelCommand;
import rip.tilly.bedwars.commands.party.PartyCommand;
import rip.tilly.bedwars.commands.setspawn.SetSpawnCommand;
@@ -19,5 +20,6 @@ public class CommandManager {
this.main.getCommand("level").setExecutor(new LevelCommand());
this.main.getCommand("xp").setExecutor(new XpCommand());
this.main.getCommand("party").setExecutor(new PartyCommand());
+ this.main.getCommand("arena").setExecutor(new ArenaCommand());
}
}
diff --git a/src/main/java/rip/tilly/bedwars/runnables/ArenaCommandRunnable.java b/src/main/java/rip/tilly/bedwars/runnables/ArenaCommandRunnable.java
new file mode 100644
index 0000000..7cddb15
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/runnables/ArenaCommandRunnable.java
@@ -0,0 +1,89 @@
+package rip.tilly.bedwars.runnables;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import rip.tilly.bedwars.BedWars;
+import rip.tilly.bedwars.game.arena.Arena;
+import rip.tilly.bedwars.game.arena.CopiedArena;
+import rip.tilly.bedwars.utils.CustomLocation;
+
+@Getter
+@AllArgsConstructor
+public class ArenaCommandRunnable implements Runnable {
+
+ private final BedWars plugin;
+ private final Arena copiedArena;
+
+ private int times;
+
+ @Override
+ public void run() {
+ this.duplicateArena(this.copiedArena, 10000, 10000);
+ }
+
+ private void duplicateArena(Arena arena, int offsetX, int offsetZ) {
+ new DuplicateArenaRunnable(this.plugin, arena, offsetX, offsetZ, 500, 500) {
+ @Override
+ public void onComplete() {
+ double minX = arena.getMin().getX() + this.getOffsetX();
+ double minZ = arena.getMin().getZ() + this.getOffsetZ();
+ double maxX = arena.getMax().getX() + this.getOffsetX();
+ double maxZ = arena.getMax().getZ() + this.getOffsetZ();
+
+ double aX = arena.getA().getX() + this.getOffsetX();
+ double aZ = arena.getA().getZ() + this.getOffsetZ();
+ double bX = arena.getB().getX() + this.getOffsetX();
+ double bZ = arena.getB().getZ() + this.getOffsetZ();
+
+ CustomLocation min = new CustomLocation(minX, arena.getMin().getY(), minZ, arena.getMin().getYaw(), arena.getMin().getPitch());
+ CustomLocation max = new CustomLocation(maxX, arena.getMax().getY(), maxZ, arena.getMax().getYaw(), arena.getMax().getPitch());
+ CustomLocation a = new CustomLocation(aX, arena.getA().getY(), aZ, arena.getA().getYaw(), arena.getA().getPitch());
+ CustomLocation b = new CustomLocation(bX, arena.getB().getY(), bZ, arena.getB().getYaw(), arena.getB().getPitch());
+
+ double aMinX = arena.getTeamAmin().getX() + this.getOffsetX();
+ double aMinZ = arena.getTeamAmin().getZ() + this.getOffsetZ();
+ double aMaxX = arena.getTeamAmax().getX() + this.getOffsetX();
+ double aMaxZ = arena.getTeamAmax().getZ() + this.getOffsetZ();
+
+ double bMinX = arena.getTeamBmin().getX() + this.getOffsetX();
+ double bMinZ = arena.getTeamBmin().getZ() + this.getOffsetZ();
+ double bMaxX = arena.getTeamBmax().getX() + this.getOffsetX();
+ double bMaxZ = arena.getTeamBmax().getZ() + this.getOffsetZ();
+
+ CustomLocation teamAmin = new CustomLocation(aMinX, arena.getTeamAmin().getY(), aMinZ, arena.getTeamAmin().getYaw(), arena.getTeamAmin().getPitch());
+ CustomLocation teamAmax = new CustomLocation(aMaxX, arena.getTeamAmax().getY(), aMaxZ, arena.getTeamAmax().getYaw(), arena.getTeamAmax().getPitch());
+ CustomLocation teamBmin = new CustomLocation(bMinX, arena.getTeamBmin().getY(), bMinZ, arena.getTeamBmin().getYaw(), arena.getTeamBmin().getPitch());
+ CustomLocation teamBmax = new CustomLocation(bMaxX, arena.getTeamBmax().getY(), bMaxZ, arena.getTeamBmax().getYaw(), arena.getTeamBmax().getPitch());
+
+ CopiedArena copiedArena = new CopiedArena(a, b, min, max, teamAmin, teamAmax, teamBmin, teamBmax);
+
+ arena.addCopiedArena(copiedArena);
+ arena.addAvailableArena(copiedArena);
+
+ String arenaPasteMessage = "[Copied Arena] - " + arena.getName() + " placed at " + (int) minX + ", " + (int) minZ + ". " + ArenaCommandRunnable.this.times + " copies remaining.";
+
+ if (--ArenaCommandRunnable.this.times > 0) {
+ ArenaCommandRunnable.this.plugin.getServer().getLogger().info(arenaPasteMessage);
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.isOp()) {
+ player.sendMessage(ChatColor.GREEN + arenaPasteMessage);
+ }
+ }
+ ArenaCommandRunnable.this.duplicateArena(arena, (int) Math.round(maxX), (int) Math.round(maxZ));
+ } else {
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ if (player.isOp()) {
+ player.sendMessage(ChatColor.GREEN + "All the copies for " + ArenaCommandRunnable.this.copiedArena.getName() + " have been pasted successfully!");
+ }
+ }
+ ArenaCommandRunnable.this.plugin.getServer().getLogger().info("All the copies for " + ArenaCommandRunnable.this.copiedArena.getName() + " have been pasted successfully!");
+ ArenaCommandRunnable.this.plugin.getArenaManager().setGeneratingArenaRunnable(ArenaCommandRunnable.this.plugin.getArenaManager().getGeneratingArenaRunnable() - 1);
+ this.getPlugin().getArenaManager().reloadArenas();
+ }
+ }
+ }.run();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/rip/tilly/bedwars/runnables/ArenaCopyRemovalRunnable.java b/src/main/java/rip/tilly/bedwars/runnables/ArenaCopyRemovalRunnable.java
new file mode 100644
index 0000000..20aafeb
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/runnables/ArenaCopyRemovalRunnable.java
@@ -0,0 +1,54 @@
+package rip.tilly.bedwars.runnables;
+
+import com.boydti.fawe.util.EditSessionBuilder;
+import com.boydti.fawe.util.TaskManager;
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.MaxChangedBlocksException;
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.blocks.BaseBlock;
+import com.sk89q.worldedit.blocks.BlockID;
+import com.sk89q.worldedit.regions.CuboidRegion;
+import org.bukkit.scheduler.BukkitRunnable;
+import rip.tilly.bedwars.BedWars;
+import rip.tilly.bedwars.game.arena.Arena;
+import rip.tilly.bedwars.game.arena.CopiedArena;
+
+public class ArenaCopyRemovalRunnable extends BukkitRunnable {
+
+ private final int number;
+ private final Arena arena;
+ private final CopiedArena arenaCopy;
+
+ private final BedWars plugin = BedWars.getInstance();
+
+ public ArenaCopyRemovalRunnable(int number, Arena arena, CopiedArena arenaCopy) {
+ this.number = number;
+ this.arena = arena;
+ this.arenaCopy = arenaCopy;
+ }
+
+ @Override
+ public void run() {
+ TaskManager.IMP.async(() -> {
+ EditSession editSession = new EditSessionBuilder(arenaCopy.getA().getWorld()).fastmode(true).allowedRegionsEverywhere().autoQueue(false).limitUnlimited().build();
+ CuboidRegion copyRegion = new CuboidRegion(
+ new Vector(arenaCopy.getMax().getX(), arenaCopy.getMax().getY(), arenaCopy.getMax().getZ()),
+ new Vector(arenaCopy.getMin().getX(), arenaCopy.getMin().getY(), arenaCopy.getMin().getZ())
+ );
+
+ try {
+ editSession.setBlocks(copyRegion, new BaseBlock(BlockID.AIR));
+ } catch (MaxChangedBlocksException e) {
+ e.getStackTrace();
+ }
+
+ editSession.flushQueue();
+ });
+
+ this.plugin.getArenasConfig().getConfig().getConfigurationSection("arenas." + arena.getName() + ".copiedArenas").set(String.valueOf(number), null);
+ this.plugin.getArenasConfig().save();
+
+ this.plugin.getArenaManager().getArena(arena.getName()).getCopiedArenas().remove(arenaCopy);
+ this.plugin.getArenaManager().getArena(arena.getName()).getAvailableArenas().remove(number);
+ }
+}
diff --git a/src/main/java/rip/tilly/bedwars/runnables/BlockPlaceRunnable.java b/src/main/java/rip/tilly/bedwars/runnables/BlockPlaceRunnable.java
new file mode 100644
index 0000000..8f1c344
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/runnables/BlockPlaceRunnable.java
@@ -0,0 +1,62 @@
+package rip.tilly.bedwars.runnables;
+
+import com.boydti.fawe.util.EditSessionBuilder;
+import com.boydti.fawe.util.TaskManager;
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.blocks.BaseBlock;
+import lombok.Getter;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+@Getter
+public abstract class BlockPlaceRunnable extends BukkitRunnable {
+
+ private final ConcurrentMap blocks;
+ private final int totalBlocks;
+ private final Iterator iterator;
+ private World world;
+ private int blockIndex = 0;
+ private int blocksPlaced = 0;
+ private boolean completed = false;
+
+ public BlockPlaceRunnable(World world, Map blocks) {
+ this.world = world;
+ this.blocks = new ConcurrentHashMap<>();
+ this.blocks.putAll(blocks);
+ this.totalBlocks = blocks.keySet().size();
+ this.iterator = blocks.keySet().iterator();
+ }
+
+ @Override
+ public void run() {
+ if (blocks.isEmpty() || !iterator.hasNext()) {
+ finish();
+ completed = true;
+ cancel();
+ return;
+ }
+
+ TaskManager.IMP.async(() -> {
+ EditSession editSession = new EditSessionBuilder(this.world.getName()).fastmode(true).allowedRegionsEverywhere().autoQueue(false).limitUnlimited().build();
+ for (Map.Entry entry : this.blocks.entrySet()) {
+ try {
+ editSession.setBlock(new Vector(entry.getKey().getBlockX(), entry.getKey().getBlockY(), entry.getKey().getZ()), new BaseBlock(entry.getValue().getTypeId(), entry.getValue().getData()));
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ editSession.flushQueue();
+ TaskManager.IMP.task(this.blocks::clear);
+ });
+ }
+
+ public abstract void finish();
+}
diff --git a/src/main/java/rip/tilly/bedwars/runnables/DuplicateArenaRunnable.java b/src/main/java/rip/tilly/bedwars/runnables/DuplicateArenaRunnable.java
new file mode 100644
index 0000000..4cf639e
--- /dev/null
+++ b/src/main/java/rip/tilly/bedwars/runnables/DuplicateArenaRunnable.java
@@ -0,0 +1,107 @@
+package rip.tilly.bedwars.runnables;
+
+import lombok.Getter;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.scheduler.BukkitRunnable;
+import rip.tilly.bedwars.BedWars;
+import rip.tilly.bedwars.game.arena.Arena;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Getter
+public abstract class DuplicateArenaRunnable extends BukkitRunnable {
+
+ private final BedWars plugin;
+ private Arena copiedArena;
+ private int offsetX;
+ private int offsetZ;
+ private int incrementX;
+ private int incrementZ;
+ private Map paste;
+
+ public DuplicateArenaRunnable(BedWars plugin, Arena copiedArena, int offsetX, int offsetZ, int incrementX, int incrementZ) {
+ this.plugin = plugin;
+ this.copiedArena = copiedArena;
+ this.offsetX = offsetX;
+ this.offsetZ = offsetZ;
+ this.incrementX = incrementX;
+ this.incrementZ = incrementZ;
+ }
+
+ @Override
+ public void run() {
+ if (this.paste == null) {
+ Map copy = this.blocksFromTwoPoints(this.copiedArena.getMin().toBukkitLocation(), this.copiedArena.getMax().toBukkitLocation());
+ this.paste = new HashMap<>();
+ for (Location loc : copy.keySet()) {
+ if (copy.get(loc).getType() != Material.AIR) {
+ this.paste.put(loc.clone().add(this.offsetX, 0, this.offsetZ), copy.get(loc));
+ }
+ }
+ copy.clear();
+ } else {
+ Map newPaste = new HashMap<>();
+ for (Location loc : this.paste.keySet()) {
+ if (this.paste.get(loc).getType() != Material.AIR) {
+ newPaste.put(loc.clone().add(this.incrementX, 0, this.incrementZ), this.paste.get(loc));
+ }
+ }
+ this.paste.clear();
+ this.paste.putAll(newPaste);
+ }
+
+ boolean safe = true;
+ for (Location loc : this.paste.keySet()) {
+ Block block = loc.getBlock();
+ if (block.getType() != Material.AIR) {
+ safe = false;
+ break;
+ }
+ }
+
+ if (!safe) {
+ this.offsetX += this.incrementX;
+ this.offsetZ += this.incrementZ;
+ this.run();
+ return;
+ }
+
+ new BlockPlaceRunnable(this.copiedArena.getA().toBukkitLocation().getWorld(), this.paste) {
+ @Override
+ public void finish() {
+ DuplicateArenaRunnable.this.onComplete();
+ }
+ }.runTaskTimer(this.plugin, 0L, 5L);
+ }
+
+ public Map blocksFromTwoPoints(Location loc1, Location loc2) {
+ Map blocks = new HashMap<>();
+
+ int topBlockX = (loc1.getBlockX() < loc2.getBlockX() ? loc2.getBlockX() : loc1.getBlockX());
+ int bottomBlockX = (loc1.getBlockX() > loc2.getBlockX() ? loc2.getBlockX() : loc1.getBlockX());
+
+ int topBlockY = (loc1.getBlockY() < loc2.getBlockY() ? loc2.getBlockY() : loc1.getBlockY());
+ int bottomBlockY = (loc1.getBlockY() > loc2.getBlockY() ? loc2.getBlockY() : loc1.getBlockY());
+
+ int topBlockZ = (loc1.getBlockZ() < loc2.getBlockZ() ? loc2.getBlockZ() : loc1.getBlockZ());
+ int bottomBlockZ = (loc1.getBlockZ() > loc2.getBlockZ() ? loc2.getBlockZ() : loc1.getBlockZ());
+
+ for (int x = bottomBlockX; x <= topBlockX; x++) {
+ for (int z = bottomBlockZ; z <= topBlockZ; z++) {
+ for (int y = bottomBlockY; y <= topBlockY; y++) {
+ Block block = loc1.getWorld().getBlockAt(x, y, z);
+ if (block.getType() != Material.AIR) {
+ blocks.put(new Location(loc1.getWorld(), x, y, z), block);
+ }
+ }
+ }
+ }
+
+ return blocks;
+ }
+
+ public abstract void onComplete();
+}